diff --git a/assets/cat-shaq.gif b/assets/cat-shaq.gif new file mode 100644 index 0000000..112fd73 Binary files /dev/null and b/assets/cat-shaq.gif differ diff --git a/bundle.js b/bundle.js index 8a9c2d2..16607f1 100644 --- a/bundle.js +++ b/bundle.js @@ -1,3875 +1,3381 @@ (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) { + console.log('Errors', errors.join(', ')); + } else { + turfIt(this.responseText); + } +} + +function transferFailed() { + console.log('Error', this.responseText); +} + +function turfIt(data) { + var results = concave(JSON.parse(data), 0.75, 'miles'); + map.getSource('results').setData(results); +} + +function turfAsync() { + map.getSource('results').setData(emptyGeoJson); + var absUrl = window.location + dataUrl; + w.postMessage([absUrl]); +} -},{}],2:[function(require,module,exports){ -// http://wiki.commonjs.org/wiki/Unit_Testing/1.0 -// -// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! -// -// Originally from narwhal.js (http://narwhaljs.org) -// Copyright (c) 2009 Thomas Robinson <280north.com> -// -// 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 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. - -// when used in node, this will actually load the util module we depend on -// versus loading the builtin util module as happens otherwise -// this is a bug in node module loading as far as I am concerned -var util = require('util/'); - -var pSlice = Array.prototype.slice; -var hasOwn = Object.prototype.hasOwnProperty; - -// 1. The assert module provides functions that throw -// AssertionError's when particular conditions are not met. The -// assert module must conform to the following interface. - -var assert = module.exports = ok; - -// 2. The AssertionError is defined in assert. -// new assert.AssertionError({ message: message, -// actual: actual, -// expected: expected }) - -assert.AssertionError = function AssertionError(options) { - this.name = 'AssertionError'; - this.actual = options.actual; - this.expected = options.expected; - this.operator = options.operator; - if (options.message) { - this.message = options.message; - this.generatedMessage = false; - } else { - this.message = getMessage(this); - this.generatedMessage = true; - } - var stackStartFunction = options.stackStartFunction || fail; +},{"./worker.js":224,"@turf/concave":2,"geobuf":15,"geojsonhint":26,"mapbox-gl":87,"pbf":195,"webworkify":221}],2:[function(require,module,exports){ +// 1. run tin on points +// 2. calculate lenth of all edges and area of all triangles +// 3. remove triangles that fail the max length test +// 4. buffer the results slightly +// 5. merge the results +var tin = require('@turf/tin'); +var union = require('@turf/union'); +var distance = require('@turf/distance'); - if (Error.captureStackTrace) { - Error.captureStackTrace(this, stackStartFunction); - } - else { - // non v8 browsers so we can have a stacktrace - var err = new Error(); - if (err.stack) { - var out = err.stack; - - // try to strip useless frames - var fn_name = stackStartFunction.name; - var idx = out.indexOf('\n' + fn_name); - if (idx >= 0) { - // once we have located the function frame - // we need to strip out everything before it (and its line) - var next_line = out.indexOf('\n', idx + 1); - out = out.substring(next_line + 1); - } +/** + * Takes a set of {@link Point|points} and returns a concave hull polygon. + * + * Internally, this uses [turf-tin](https://github.com/Turfjs/turf-tin) to generate geometries. + * + * @param {FeatureCollection} points input points + * @param {number} maxEdge the size of an edge necessary for part of the + * hull to become concave (in miles) + * @param {string} units used for maxEdge distance (miles or kilometers) + * @returns {Feature} a concave hull + * @throws {Error} if maxEdge parameter is missing + * @throws {Error} if units parameter is missing + * @example + * var points = { + * "type": "FeatureCollection", + * "features": [ + * { + * "type": "Feature", + * "properties": {}, + * "geometry": { + * "type": "Point", + * "coordinates": [-63.601226, 44.642643] + * } + * }, { + * "type": "Feature", + * "properties": {}, + * "geometry": { + * "type": "Point", + * "coordinates": [-63.591442, 44.651436] + * } + * }, { + * "type": "Feature", + * "properties": {}, + * "geometry": { + * "type": "Point", + * "coordinates": [-63.580799, 44.648749] + * } + * }, { + * "type": "Feature", + * "properties": {}, + * "geometry": { + * "type": "Point", + * "coordinates": [-63.573589, 44.641788] + * } + * }, { + * "type": "Feature", + * "properties": {}, + * "geometry": { + * "type": "Point", + * "coordinates": [-63.587665, 44.64533] + * } + * }, { + * "type": "Feature", + * "properties": {}, + * "geometry": { + * "type": "Point", + * "coordinates": [-63.595218, 44.64765] + * } + * } + * ] + * }; + * + * var hull = turf.concave(points, 1, 'miles'); + * + * var resultFeatures = points.features.concat(hull); + * var result = { + * "type": "FeatureCollection", + * "features": resultFeatures + * }; + * + * //=result + */ +function concave(points, maxEdge, units) { + if (typeof maxEdge !== 'number') throw new Error('maxEdge parameter is required'); + if (typeof units !== 'string') throw new Error('units parameter is required'); - this.stack = out; - } - } -}; + var tinPolys = tin(points); + var filteredPolys = tinPolys.features.filter(filterTriangles); + tinPolys.features = filteredPolys; -// assert.AssertionError instanceof Error -util.inherits(assert.AssertionError, Error); + function filterTriangles(triangle) { + var pt1 = triangle.geometry.coordinates[0][0]; + var pt2 = triangle.geometry.coordinates[0][1]; + var pt3 = triangle.geometry.coordinates[0][2]; + var dist1 = distance(pt1, pt2, units); + var dist2 = distance(pt2, pt3, units); + var dist3 = distance(pt1, pt3, units); + return (dist1 <= maxEdge && dist2 <= maxEdge && dist3 <= maxEdge); + } -function replacer(key, value) { - if (util.isUndefined(value)) { - return '' + value; - } - if (util.isNumber(value) && !isFinite(value)) { - return value.toString(); - } - if (util.isFunction(value) || util.isRegExp(value)) { - return value.toString(); - } - return value; + return merge(tinPolys); } -function truncate(s, n) { - if (util.isString(s)) { - return s.length < n ? s : s.slice(0, n); - } else { - return s; - } -} +function merge(polygons) { + var merged = JSON.parse(JSON.stringify(polygons.features[0])), + features = polygons.features; -function getMessage(self) { - return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' + - self.operator + ' ' + - truncate(JSON.stringify(self.expected, replacer), 128); + for (var i = 0, len = features.length; i < len; i++) { + var poly = features[i]; + if (poly.geometry) { + merged = union(merged, poly); + } + } + return merged; } -// At present only the three keys mentioned above are used and -// understood by the spec. Implementations or sub modules can pass -// other keys to the AssertionError's constructor - they will be -// ignored. +module.exports = concave; -// 3. All of the following functions must throw an AssertionError -// when a corresponding condition is not met, with a message that -// may be undefined if not provided. All assertion methods provide -// both the actual and expected values to the assertion error for -// display purposes. +},{"@turf/distance":3,"@turf/tin":6,"@turf/union":7}],3:[function(require,module,exports){ +var getCoord = require('@turf/invariant').getCoord; +var radiansToDistance = require('@turf/helpers').radiansToDistance; +//http://en.wikipedia.org/wiki/Haversine_formula +//http://www.movable-type.co.uk/scripts/latlong.html -function fail(actual, expected, message, operator, stackStartFunction) { - throw new assert.AssertionError({ - message: message, - actual: actual, - expected: expected, - operator: operator, - stackStartFunction: stackStartFunction - }); -} +/** + * 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 {Feature} from origin point + * @param {Feature} to destination point + * @param {String} [units=kilometers] can be degrees, radians, miles, or kilometers + * @return {Number} distance between the two points + * @example + * var from = { + * "type": "Feature", + * "properties": {}, + * "geometry": { + * "type": "Point", + * "coordinates": [-75.343, 39.984] + * } + * }; + * var to = { + * "type": "Feature", + * "properties": {}, + * "geometry": { + * "type": "Point", + * "coordinates": [-75.534, 39.123] + * } + * }; + * var units = "miles"; + * + * var points = { + * "type": "FeatureCollection", + * "features": [from, to] + * }; + * + * //=points + * + * var distance = turf.distance(from, to, units); + * + * //=distance + */ +module.exports = function (from, to, units) { + var degrees2radians = Math.PI / 180; + var coordinates1 = getCoord(from); + var coordinates2 = getCoord(to); + var dLat = degrees2radians * (coordinates2[1] - coordinates1[1]); + var dLon = degrees2radians * (coordinates2[0] - coordinates1[0]); + var lat1 = degrees2radians * coordinates1[1]; + var lat2 = degrees2radians * coordinates2[1]; -// EXTENSION! allows for well behaved errors defined elsewhere. -assert.fail = fail; + var a = Math.pow(Math.sin(dLat / 2), 2) + + Math.pow(Math.sin(dLon / 2), 2) * Math.cos(lat1) * Math.cos(lat2); -// 4. Pure assertion tests whether a value is truthy, as determined -// by !!guard. -// assert.ok(guard, message_opt); -// This statement is equivalent to assert.equal(true, !!guard, -// message_opt);. To test strictly for the value true, use -// assert.strictEqual(true, guard, message_opt);. + return radiansToDistance(2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)), units); +}; -function ok(value, message) { - if (!value) fail(value, true, message, '==', assert.ok); +},{"@turf/helpers":4,"@turf/invariant":5}],4:[function(require,module,exports){ +/** + * Wraps a GeoJSON {@link Geometry} in a GeoJSON {@link Feature}. + * + * @name feature + * @param {Geometry} geometry input geometry + * @param {Object} properties properties + * @returns {FeatureCollection} a FeatureCollection of input features + * @example + * var geometry = { + * "type": "Point", + * "coordinates": [ + * 67.5, + * 32.84267363195431 + * ] + * } + * + * var feature = turf.feature(geometry); + * + * //=feature + */ +function feature(geometry, properties) { + return { + type: 'Feature', + properties: properties || {}, + geometry: geometry + }; } -assert.ok = ok; -// 5. The equality assertion tests shallow, coercive equality with -// ==. -// assert.equal(actual, expected, message_opt); +module.exports.feature = feature; -assert.equal = function equal(actual, expected, message) { - if (actual != expected) fail(actual, expected, message, '==', assert.equal); +/** + * Takes coordinates and properties (optional) and returns a new {@link Point} feature. + * + * @name point + * @param {number[]} coordinates longitude, latitude position (each in decimal degrees) + * @param {Object=} properties an Object that is used as the {@link Feature}'s + * properties + * @returns {Feature} a Point feature + * @example + * var pt1 = turf.point([-75.343, 39.984]); + * + * //=pt1 + */ +module.exports.point = function (coordinates, properties) { + 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'); + return feature({ + type: 'Point', + coordinates: coordinates.slice() + }, properties); }; -// 6. The non-equality assertion tests for whether two objects are not equal -// with != assert.notEqual(actual, expected, message_opt); +/** + * Takes an array of LinearRings and optionally an {@link Object} with properties and returns a {@link Polygon} feature. + * + * @name polygon + * @param {Array>>} coordinates an array of LinearRings + * @param {Object=} properties a properties object + * @returns {Feature} 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 + */ +module.exports.polygon = function (coordinates, properties) { -assert.notEqual = function notEqual(actual, expected, message) { - if (actual == expected) { - fail(actual, expected, message, '!=', assert.notEqual); - } -}; + if (!coordinates) throw new Error('No coordinates passed'); -// 7. The equivalence assertion tests a deep equality relation. -// assert.deepEqual(actual, expected, message_opt); + 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++) { + if (ring[ring.length - 1][j] !== ring[0][j]) { + throw new Error('First and last Position are not equivalent.'); + } + } + } -assert.deepEqual = function deepEqual(actual, expected, message) { - if (!_deepEqual(actual, expected)) { - fail(actual, expected, message, 'deepEqual', assert.deepEqual); - } + return feature({ + type: 'Polygon', + coordinates: coordinates + }, properties); }; -function _deepEqual(actual, expected) { - // 7.1. All identical values are equivalent, as determined by ===. - if (actual === expected) { - return true; - - } else if (util.isBuffer(actual) && util.isBuffer(expected)) { - if (actual.length != expected.length) return false; - - for (var i = 0; i < actual.length; i++) { - if (actual[i] !== expected[i]) return false; +/** + * Creates a {@link LineString} based on a + * coordinate array. Properties can be added optionally. + * + * @name lineString + * @param {Array>} coordinates an array of Positions + * @param {Object=} properties an Object of key-value pairs to add as properties + * @returns {Feature} 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 + */ +module.exports.lineString = function (coordinates, properties) { + if (!coordinates) { + throw new Error('No coordinates passed'); } + return feature({ + type: 'LineString', + coordinates: coordinates + }, properties); +}; - return true; - - // 7.2. If the expected value is a Date object, the actual value is - // equivalent if it is also a Date object that refers to the same time. - } else if (util.isDate(actual) && util.isDate(expected)) { - return actual.getTime() === expected.getTime(); - - // 7.3 If the expected value is a RegExp object, the actual value is - // equivalent if it is also a RegExp object with the same source and - // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). - } else if (util.isRegExp(actual) && util.isRegExp(expected)) { - return actual.source === expected.source && - actual.global === expected.global && - actual.multiline === expected.multiline && - actual.lastIndex === expected.lastIndex && - actual.ignoreCase === expected.ignoreCase; - - // 7.4. Other pairs that do not both pass typeof value == 'object', - // equivalence is determined by ==. - } else if (!util.isObject(actual) && !util.isObject(expected)) { - return actual == expected; - - // 7.5 For all other Object pairs, including Array objects, equivalence is - // determined by having the same number of owned properties (as verified - // with Object.prototype.hasOwnProperty.call), the same set of keys - // (although not necessarily the same order), equivalent values for every - // corresponding key, and an identical 'prototype' property. Note: this - // accounts for both named and indexed properties on Arrays. - } else { - return objEquiv(actual, expected); - } -} - -function isArguments(object) { - return Object.prototype.toString.call(object) == '[object Arguments]'; -} - -function objEquiv(a, b) { - if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b)) - return false; - // an identical 'prototype' property. - if (a.prototype !== b.prototype) return false; - // if one is a primitive, the other must be same - if (util.isPrimitive(a) || util.isPrimitive(b)) { - return a === b; - } - var aIsArgs = isArguments(a), - bIsArgs = isArguments(b); - if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) - return false; - if (aIsArgs) { - a = pSlice.call(a); - b = pSlice.call(b); - return _deepEqual(a, b); - } - var ka = objectKeys(a), - kb = objectKeys(b), - key, i; - // having the same number of owned properties (keys incorporates - // hasOwnProperty) - if (ka.length != kb.length) - return false; - //the same set of keys (although not necessarily the same order), - ka.sort(); - kb.sort(); - //~~~cheap key test - for (i = ka.length - 1; i >= 0; i--) { - if (ka[i] != kb[i]) - return false; - } - //equivalent values for every corresponding key, and - //~~~possibly expensive deep test - for (i = ka.length - 1; i >= 0; i--) { - key = ka[i]; - if (!_deepEqual(a[key], b[key])) return false; - } - return true; -} - -// 8. The non-equivalence assertion tests for any deep inequality. -// assert.notDeepEqual(actual, expected, message_opt); - -assert.notDeepEqual = function notDeepEqual(actual, expected, message) { - if (_deepEqual(actual, expected)) { - fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); - } +/** + * Takes one or more {@link Feature|Features} and creates a {@link FeatureCollection}. + * + * @name featureCollection + * @param {Feature[]} features input features + * @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 fc = turf.featureCollection(features); + * + * //=fc + */ +module.exports.featureCollection = function (features) { + return { + type: 'FeatureCollection', + features: features + }; }; -// 9. The strict equality assertion tests strict equality, as determined by ===. -// assert.strictEqual(actual, expected, message_opt); - -assert.strictEqual = function strictEqual(actual, expected, message) { - if (actual !== expected) { - fail(actual, expected, message, '===', assert.strictEqual); - } +/** + * Creates a {@link Feature} based on a + * coordinate array. Properties can be added optionally. + * + * @name multiLineString + * @param {Array>>} coordinates an array of LineStrings + * @param {Object=} properties an Object of key-value pairs to add as properties + * @returns {Feature} a MultiLineString feature + * @throws {Error} if no coordinates are passed + * @example + * var multiLine = turf.multiLineString([[[0,0],[10,10]]]); + * + * //=multiLine + * + */ +module.exports.multiLineString = function (coordinates, properties) { + if (!coordinates) { + throw new Error('No coordinates passed'); + } + return feature({ + type: 'MultiLineString', + coordinates: coordinates + }, properties); }; -// 10. The strict non-equality assertion tests for strict inequality, as -// determined by !==. assert.notStrictEqual(actual, expected, message_opt); - -assert.notStrictEqual = function notStrictEqual(actual, expected, message) { - if (actual === expected) { - fail(actual, expected, message, '!==', assert.notStrictEqual); - } +/** + * Creates a {@link Feature} based on a + * coordinate array. Properties can be added optionally. + * + * @name multiPoint + * @param {Array>} coordinates an array of Positions + * @param {Object=} properties an Object of key-value pairs to add as properties + * @returns {Feature} a MultiPoint feature + * @throws {Error} if no coordinates are passed + * @example + * var multiPt = turf.multiPoint([[0,0],[10,10]]); + * + * //=multiPt + * + */ +module.exports.multiPoint = function (coordinates, properties) { + if (!coordinates) { + throw new Error('No coordinates passed'); + } + return feature({ + type: 'MultiPoint', + coordinates: coordinates + }, properties); }; -function expectedException(actual, expected) { - if (!actual || !expected) { - return false; - } - - if (Object.prototype.toString.call(expected) == '[object RegExp]') { - return expected.test(actual); - } else if (actual instanceof expected) { - return true; - } else if (expected.call({}, actual) === true) { - return true; - } - - return false; -} - -function _throws(shouldThrow, block, expected, message) { - var actual; - - if (util.isString(expected)) { - message = expected; - expected = null; - } - - try { - block(); - } catch (e) { - actual = e; - } - - message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + - (message ? ' ' + message : '.'); - - if (shouldThrow && !actual) { - fail(actual, expected, 'Missing expected exception' + message); - } - - if (!shouldThrow && expectedException(actual, expected)) { - fail(actual, expected, 'Got unwanted exception' + message); - } - - if ((shouldThrow && actual && expected && - !expectedException(actual, expected)) || (!shouldThrow && actual)) { - throw actual; - } -} -// 11. Expected to throw an error: -// assert.throws(block, Error_opt, message_opt); - -assert.throws = function(block, /*optional*/error, /*optional*/message) { - _throws.apply(this, [true].concat(pSlice.call(arguments))); +/** + * Creates a {@link Feature} based on a + * coordinate array. Properties can be added optionally. + * + * @name multiPolygon + * @param {Array>>>} coordinates an array of Polygons + * @param {Object=} properties an Object of key-value pairs to add as properties + * @returns {Feature} 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 + * + */ +module.exports.multiPolygon = function (coordinates, properties) { + if (!coordinates) { + throw new Error('No coordinates passed'); + } + return feature({ + type: 'MultiPolygon', + coordinates: coordinates + }, properties); }; -// EXTENSION! This is annoying to write outside this module. -assert.doesNotThrow = function(block, /*optional*/message) { - _throws.apply(this, [false].concat(pSlice.call(arguments))); +/** + * Creates a {@link Feature} 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 + * @returns {Feature} a geometrycollection feature + * @example + * var pt = { + * "type": "Point", + * "coordinates": [100, 0] + * }; + * var line = { + * "type": "LineString", + * "coordinates": [ [101, 0], [102, 1] ] + * }; + * var collection = turf.geometrycollection([[0,0],[10,10]]); + * + * //=collection + */ +module.exports.geometryCollection = function (geometries, properties) { + return feature({ + type: 'GeometryCollection', + geometries: geometries + }, properties); +}; + +var factors = { + miles: 3960, + nauticalmiles: 3441.145, + degrees: 57.2957795, + radians: 1, + inches: 250905600, + yards: 6969600, + meters: 6373000, + metres: 6373000, + kilometers: 6373, + kilometres: 6373 }; -assert.ifError = function(err) { if (err) {throw err;}}; - -var objectKeys = Object.keys || function (obj) { - var keys = []; - for (var key in obj) { - if (hasOwn.call(obj, key)) keys.push(key); - } - return keys; +/* + * Convert a distance measurement from radians to a more friendly unit. + * + * @name radiansToDistance + * @param {number} distance in radians across the sphere + * @param {string=kilometers} units: one of miles, nauticalmiles, degrees, radians, + * inches, yards, metres, meters, kilometres, kilometers. + * @returns {number} distance + */ +module.exports.radiansToDistance = function (radians, units) { + var factor = factors[units || 'kilometers']; + if (factor === undefined) { + throw new Error('Invalid unit'); + } + return radians * factor; }; -},{"util/":11}],3:[function(require,module,exports){ -(function (global){ -/*! - * The buffer module from node.js, for the browser. +/* + * Convert a distance measurement from a real-world unit into radians * - * @author Feross Aboukhadijeh - * @license MIT + * @name distanceToRadians + * @param {number} distance in real units + * @param {string=kilometers} units: one of miles, nauticalmiles, degrees, radians, + * inches, yards, metres, meters, kilometres, kilometers. + * @returns {number} radians */ -/* eslint-disable no-proto */ - -'use strict' - -var base64 = require('base64-js') -var ieee754 = require('ieee754') -var isArray = require('isarray') - -exports.Buffer = Buffer -exports.SlowBuffer = SlowBuffer -exports.INSPECT_MAX_BYTES = 50 -Buffer.poolSize = 8192 // not used by this implementation +module.exports.distanceToRadians = function (distance, units) { + var factor = factors[units || 'kilometers']; + if (factor === undefined) { + throw new Error('Invalid unit'); + } + return distance / factor; +}; -var rootParent = {} +/* + * Convert a distance measurement from a real-world unit into degrees + * + * @name distanceToRadians + * @param {number} distance in real units + * @param {string=kilometers} units: one of miles, nauticalmiles, degrees, radians, + * inches, yards, metres, meters, kilometres, kilometers. + * @returns {number} degrees + */ +module.exports.distanceToDegrees = function (distance, units) { + var factor = factors[units || 'kilometers']; + if (factor === undefined) { + throw new Error('Invalid unit'); + } + return (distance / factor) * 57.2958; +}; +},{}],5:[function(require,module,exports){ /** - * If `Buffer.TYPED_ARRAY_SUPPORT`: - * === true Use Uint8Array implementation (fastest) - * === false Use 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+. - * - * Due to various browser bugs, sometimes the Object implementation will be used even - * when the browser supports typed arrays. + * Unwrap a coordinate from a Feature with a Point geometry, a Point + * geometry, or a single coordinate. * - * Note: - * - * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, - * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. - * - * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. - * - * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of - * incorrect length in some situations. - - * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they - * get the Object implementation, which is slower but behaves correctly. + * @param {*} obj any value + * @returns {Array} a coordinate */ -Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined - ? global.TYPED_ARRAY_SUPPORT - : typedArraySupport() - -function typedArraySupport () { - try { - var arr = new Uint8Array(1) - arr.foo = function () { return 42 } - return arr.foo() === 42 && // typed array instances can be augmented - typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` - arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` - } catch (e) { - return false - } -} - -function kMaxLength () { - return Buffer.TYPED_ARRAY_SUPPORT - ? 0x7fffffff - : 0x3fffffff +function getCoord(obj) { + if (Array.isArray(obj) && + typeof obj[0] === 'number' && + typeof obj[1] === 'number') { + return obj; + } else if (obj) { + if (obj.type === 'Feature' && + obj.geometry && + obj.geometry.type === 'Point' && + Array.isArray(obj.geometry.coordinates)) { + return obj.geometry.coordinates; + } else if (obj.type === 'Point' && + Array.isArray(obj.coordinates)) { + return obj.coordinates; + } + } + throw new Error('A coordinate, feature, or point geometry is required'); } /** - * 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. + * Enforce expectations about types of GeoJSON objects for Turf. * - * The `Uint8Array` prototype remains unmodified. + * @alias 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 Buffer (arg) { - if (!(this instanceof Buffer)) { - // Avoid going through an ArgumentsAdaptorTrampoline in the common case. - if (arguments.length > 1) return new Buffer(arg, arguments[1]) - return new Buffer(arg) - } - - if (!Buffer.TYPED_ARRAY_SUPPORT) { - this.length = 0 - this.parent = undefined - } - - // Common case. - if (typeof arg === 'number') { - return fromNumber(this, arg) - } - - // Slightly less common case. - if (typeof arg === 'string') { - return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8') - } - - // Unusual. - return fromObject(this, arg) -} +function geojsonType(value, type, name) { + if (!type || !name) throw new Error('type and name required'); -// TODO: Legacy, not needed anymore. Remove in next major version. -Buffer._augment = function (arr) { - arr.__proto__ = Buffer.prototype - return arr + if (!value || value.type !== type) { + throw new Error('Invalid input to ' + name + ': must be a ' + type + ', given ' + value.type); + } } -function fromNumber (that, length) { - that = allocate(that, length < 0 ? 0 : checked(length) | 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) { - for (var i = 0; i < length; i++) { - that[i] = 0 +/** + * Enforce expectations about types of {@link Feature} inputs for Turf. + * Internally this uses {@link geojsonType} to judge geometry types. + * + * @alias 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 (!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); } - } - return that } -function fromString (that, string, encoding) { - if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8' - - // Assumption: byteLength() return value is always < kMaxLength. - var length = byteLength(string, encoding) | 0 - that = allocate(that, length) - - that.write(string, encoding) - return that +/** + * Enforce expectations about types of {@link FeatureCollection} inputs for Turf. + * Internally this uses {@link geojsonType} to judge geometry types. + * + * @alias 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 (!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); + } + } } -function fromObject (that, object) { - if (Buffer.isBuffer(object)) return fromBuffer(that, object) +module.exports.geojsonType = geojsonType; +module.exports.collectionOf = collectionOf; +module.exports.featureOf = featureOf; +module.exports.getCoord = getCoord; - if (isArray(object)) return fromArray(that, object) +},{}],6:[function(require,module,exports){ +//http://en.wikipedia.org/wiki/Delaunay_triangulation +//https://github.com/ironwallaby/delaunay +var polygon = require('@turf/helpers').polygon; +var featurecollection = require('@turf/helpers').featureCollection; - if (object == null) { - throw new TypeError('must start with number, buffer, array or string') - } +/** + * Takes a set of {@link Point|points} and the name of a z-value property and + * creates a [Triangulated Irregular Network](http://en.wikipedia.org/wiki/Triangulated_irregular_network), + * or a TIN for short, returned as a collection of Polygons. These are often used + * for developing elevation contour maps or stepped heat visualizations. + * + * This triangulates the points, as well as adds properties called `a`, `b`, + * and `c` representing the value of the given `propertyName` at each of + * the points that represent the corners of the triangle. + * + * @name tin + * @param {FeatureCollection} points input points + * @param {String=} z name of the property from which to pull z values + * This is optional: if not given, then there will be no extra data added to the derived triangles. + * @return {FeatureCollection} TIN output + * @example + * // generate some random point data + * var points = turf.random('points', 30, { + * bbox: [50, 30, 70, 50] + * }); + * //=points + * // add a random property to each point between 0 and 9 + * for (var i = 0; i < points.features.length; i++) { + * points.features[i].properties.z = ~~(Math.random() * 9); + * } + * var tin = turf.tin(points, 'z') + * for (var i = 0; i < tin.features.length; i++) { + * var properties = tin.features[i].properties; + * // roughly turn the properties of each + * // triangle into a fill color + * // so we can visualize the result + * properties.fill = '#' + properties.a + + * properties.b + properties.c; + * } + * //=tin + */ +module.exports = function (points, z) { + //break down points + return featurecollection(triangulate(points.features.map(function (p) { + var point = { + x: p.geometry.coordinates[0], + y: p.geometry.coordinates[1] + }; + if (z) point.z = p.properties[z]; + return point; + })).map(function (triangle) { + return polygon([[ + [triangle.a.x, triangle.a.y], + [triangle.b.x, triangle.b.y], + [triangle.c.x, triangle.c.y], + [triangle.a.x, triangle.a.y] + ]], { + a: triangle.a.z, + b: triangle.b.z, + c: triangle.c.z + }); + })); +}; - if (typeof ArrayBuffer !== 'undefined') { - if (object.buffer instanceof ArrayBuffer) { - return fromTypedArray(that, object) - } - if (object instanceof ArrayBuffer) { - return fromArrayBuffer(that, object) +function Triangle(a, b, c) { + this.a = a; + this.b = b; + this.c = c; + + var A = b.x - a.x, + B = b.y - a.y, + C = c.x - a.x, + D = c.y - a.y, + E = A * (a.x + b.x) + B * (a.y + b.y), + F = C * (a.x + c.x) + D * (a.y + c.y), + G = 2 * (A * (c.y - b.y) - B * (c.x - b.x)), + minx, miny, dx, dy; + + // If the points of the triangle are collinear, then just find the + // extremes and use the midpoint as the center of the circumcircle. + if (Math.abs(G) < 0.000001) { + minx = Math.min(a.x, b.x, c.x); + miny = Math.min(a.y, b.y, c.y); + dx = (Math.max(a.x, b.x, c.x) - minx) * 0.5; + dy = (Math.max(a.y, b.y, c.y) - miny) * 0.5; + + this.x = minx + dx; + this.y = miny + dy; + this.r = dx * dx + dy * dy; + } else { + this.x = (D * E - B * F) / G; + this.y = (A * F - C * E) / G; + dx = this.x - a.x; + dy = this.y - a.y; + this.r = dx * dx + dy * dy; } - } - - if (object.length) return fromArrayLike(that, object) - - return fromJsonObject(that, object) } -function fromBuffer (that, buffer) { - var length = checked(buffer.length) | 0 - that = allocate(that, length) - buffer.copy(that, 0, 0, length) - return that +function byX(a, b) { + return b.x - a.x; } -function fromArray (that, array) { - var length = checked(array.length) | 0 - that = allocate(that, length) - for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 - } - return that -} - -// Duplicate of fromArray() to keep fromArray() monomorphic. -function fromTypedArray (that, array) { - var length = checked(array.length) | 0 - that = allocate(that, length) - // Truncating the elements is probably not what people expect from typed - // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior - // of the old Buffer constructor. - for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 +function dedup(edges) { + var j = edges.length, + a, b, i, m, n; + + outer: + while (j) { + b = edges[--j]; + a = edges[--j]; + i = j; + while (i) { + n = edges[--i]; + m = edges[--i]; + if ((a === m && b === n) || (a === n && b === m)) { + edges.splice(j, 2); + edges.splice(i, 2); + j -= 2; + continue outer; + } + } } - return that } -function fromArrayBuffer (that, array) { - array.byteLength // this throws if `array` is not a valid ArrayBuffer +function triangulate(vertices) { + // Bail if there aren't enough vertices to form any triangles. + if (vertices.length < 3) + return []; - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - that = new Uint8Array(array) - that.__proto__ = Buffer.prototype - } else { - // Fallback: Return an object instance of the Buffer class - that = fromTypedArray(that, new Uint8Array(array)) - } - return that -} + // Ensure the vertex array is in order of descending X coordinate + // (which is needed to ensure a subquadratic runtime), and then find + // the bounding box around the points. + vertices.sort(byX); + + var i = vertices.length - 1, + xmin = vertices[i].x, + xmax = vertices[0].x, + ymin = vertices[i].y, + ymax = ymin; + + while (i--) { + if (vertices[i].y < ymin) + ymin = vertices[i].y; + if (vertices[i].y > ymax) + ymax = vertices[i].y; + } + + //Find a supertriangle, which is a triangle that surrounds all the + //vertices. This is used like something of a sentinel value to remove + //cases in the main algorithm, and is removed before we return any + // results. + + // Once found, put it in the "open" list. (The "open" list is for + // triangles who may still need to be considered; the "closed" list is + // for triangles which do not.) + var dx = xmax - xmin, + dy = ymax - ymin, + dmax = (dx > dy) ? dx : dy, + xmid = (xmax + xmin) * 0.5, + ymid = (ymax + ymin) * 0.5, + open = [ + new Triangle({ + x: xmid - 20 * dmax, + y: ymid - dmax, + __sentinel: true + }, { + x: xmid, + y: ymid + 20 * dmax, + __sentinel: true + }, { + x: xmid + 20 * dmax, + y: ymid - dmax, + __sentinel: true + } + )], + closed = [], + edges = [], + j, a, b; -function fromArrayLike (that, array) { - var length = checked(array.length) | 0 - that = allocate(that, length) - for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 - } - return that -} + // Incrementally add each vertex to the mesh. + i = vertices.length; + while (i--) { + // For each open triangle, check to see if the current point is + // inside it's circumcircle. If it is, remove the triangle and add + // it's edges to an edge list. + edges.length = 0; + j = open.length; + while (j--) { + // If this point is to the right of this triangle's circumcircle, + // then this triangle should never get checked again. Remove it + // from the open list, add it to the closed list, and skip. + dx = vertices[i].x - open[j].x; + if (dx > 0 && dx * dx > open[j].r) { + closed.push(open[j]); + open.splice(j, 1); + continue; + } -// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object. -// Returns a zero-length buffer for inputs that don't conform to the spec. -function fromJsonObject (that, object) { - var array - var length = 0 + // If not, skip this triangle. + dy = vertices[i].y - open[j].y; + if (dx * dx + dy * dy > open[j].r) + continue; - if (object.type === 'Buffer' && isArray(object.data)) { - array = object.data - length = checked(array.length) | 0 - } - that = allocate(that, length) + // Remove the triangle and add it's edges to the edge list. + edges.push( + open[j].a, open[j].b, + open[j].b, open[j].c, + open[j].c, open[j].a + ); + open.splice(j, 1); + } - for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 - } - return that -} - -if (Buffer.TYPED_ARRAY_SUPPORT) { - Buffer.prototype.__proto__ = Uint8Array.prototype - Buffer.__proto__ = Uint8Array - if (typeof Symbol !== 'undefined' && Symbol.species && - Buffer[Symbol.species] === Buffer) { - // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 - Object.defineProperty(Buffer, Symbol.species, { - value: null, - configurable: true - }) - } -} else { - // pre-set for values that may exist in the future - Buffer.prototype.length = undefined - Buffer.prototype.parent = undefined -} + // Remove any doubled edges. + dedup(edges); -function allocate (that, length) { - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - that = new Uint8Array(length) - that.__proto__ = Buffer.prototype - } else { - // Fallback: Return an object instance of the Buffer class - that.length = length - } + // Add a new triangle for each edge. + j = edges.length; + while (j) { + b = edges[--j]; + a = edges[--j]; + open.push(new Triangle(a, b, vertices[i])); + } + } - var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1 - if (fromPool) that.parent = rootParent + // Copy any remaining open triangles to the closed list, and then + // remove any triangles that share a vertex with the supertriangle. + Array.prototype.push.apply(closed, open); - return that -} + i = closed.length; + while (i--) + if (closed[i].a.__sentinel || + closed[i].b.__sentinel || + closed[i].c.__sentinel) + closed.splice(i, 1); -function checked (length) { - // Note: cannot use `length < kMaxLength` here because that fails when - // length is NaN (which is otherwise coerced to zero.) - if (length >= kMaxLength()) { - throw new RangeError('Attempt to allocate Buffer larger than maximum ' + - 'size: 0x' + kMaxLength().toString(16) + ' bytes') - } - return length | 0 + return closed; } -function SlowBuffer (subject, encoding) { - if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding) +},{"@turf/helpers":4}],7:[function(require,module,exports){ +// look here for help http://svn.osgeo.org/grass/grass/branches/releasebranch_6_4/vector/v.overlay/main.c +//must be array of polygons - var buf = new Buffer(subject, encoding) - delete buf.parent - return buf -} +// depend on jsts for now https://github.com/bjornharrtell/jsts/blob/master/examples/overlay.html -Buffer.isBuffer = function isBuffer (b) { - return !!(b != null && b._isBuffer) -} +var jsts = require('jsts'); -Buffer.compare = function compare (a, b) { - if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { - throw new TypeError('Arguments must be Buffers') - } +/** + * Takes two or more {@link Polygon|polygons} and returns a combined polygon. If the input polygons are not contiguous, this function returns a {@link MultiPolygon} feature. + * + * @name union + * @param {...Feature} A polygon to combine + * @return {Feature<(Polygon|MultiPolygon)>} a combined {@link Polygon} or {@link MultiPolygon} feature + * @example + * var poly1 = { + * "type": "Feature", + * "properties": { + * "fill": "#0f0" + * }, + * "geometry": { + * "type": "Polygon", + * "coordinates": [[ + * [-82.574787, 35.594087], + * [-82.574787, 35.615581], + * [-82.545261, 35.615581], + * [-82.545261, 35.594087], + * [-82.574787, 35.594087] + * ]] + * } + * }; + * var poly2 = { + * "type": "Feature", + * "properties": { + * "fill": "#00f" + * }, + * "geometry": { + * "type": "Polygon", + * "coordinates": [[ + * [-82.560024, 35.585153], + * [-82.560024, 35.602602], + * [-82.52964, 35.602602], + * [-82.52964, 35.585153], + * [-82.560024, 35.585153] + * ]] + * } + * }; + * var polygons = { + * "type": "FeatureCollection", + * "features": [poly1, poly2] + * }; + * + * var union = turf.union(poly1, poly2); + * + * //=polygons + * + * //=union + */ +module.exports = function () { + var reader = new jsts.io.GeoJSONReader(); + var result = reader.read(JSON.stringify(arguments[0].geometry)); - if (a === b) return 0 + for (var i = 1; i < arguments.length; i++) { + result = result.union(reader.read(JSON.stringify(arguments[i].geometry))); + } - var x = a.length - var y = b.length + var writer = new jsts.io.GeoJSONWriter(); + result = writer.write(result); - var i = 0 - var len = Math.min(x, y) - while (i < len) { - if (a[i] !== b[i]) break + return { + type: 'Feature', + geometry: result, + properties: arguments[0].properties + }; +}; - ++i - } +},{"jsts":8}],8:[function(require,module,exports){ +// JSTS. See https://github.com/bjornharrtell/jsts +// Licenses: +// https://github.com/bjornharrtell/jsts/blob/master/LICENSE_EDLv1.txt +// https://github.com/bjornharrtell/jsts/blob/master/LICENSE_EPLv1.txt +// https://github.com/bjornharrtell/jsts/blob/master/LICENSE_LICENSE_ES6_COLLECTIONS.txt +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(t.jsts=t.jsts||{})}(this,function(t){"use strict";function e(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])}function n(){}function i(){}function r(){}function s(){}function o(){}function a(){}function u(){}function l(t){this.name="RuntimeException",this.message=t,this.stack=(new Error).stack,Error.call(this,t)}function h(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t}function c(){if(0===arguments.length)l.call(this);else if(1===arguments.length){var t=arguments[0];l.call(this,t)}}function f(){}function g(){if(this.x=null,this.y=null,this.z=null,0===arguments.length)g.call(this,0,0);else if(1===arguments.length){var t=arguments[0];g.call(this,t.x,t.y,t.z)}else if(2===arguments.length){var e=arguments[0],n=arguments[1];g.call(this,e,n,g.NULL_ORDINATE)}else if(3===arguments.length){var i=arguments[0],r=arguments[1],s=arguments[2];this.x=i,this.y=r,this.z=s}}function d(){if(this.dimensionsToTest=2,0===arguments.length)d.call(this,2);else if(1===arguments.length){var t=arguments[0];if(2!==t&&3!==t)throw new i("only 2 or 3 dimensions may be specified");this.dimensionsToTest=t}}function p(){}function v(){}function m(t){this.message=t||""}function y(){}function x(t){this.message=t||""}function E(t){this.message=t||""}function I(){this.array_=[],arguments[0]instanceof v&&this.addAll(arguments[0])}function N(){if(I.apply(this),0===arguments.length);else if(1===arguments.length){var t=arguments[0];this.ensureCapacity(t.length),this.add(t,!0)}else if(2===arguments.length){var e=arguments[0],n=arguments[1];this.ensureCapacity(e.length),this.add(e,n)}}function C(){if(this.minx=null,this.maxx=null,this.miny=null,this.maxy=null,0===arguments.length)this.init();else if(1===arguments.length){if(arguments[0]instanceof g){var t=arguments[0];this.init(t.x,t.x,t.y,t.y)}else if(arguments[0]instanceof C){var e=arguments[0];this.init(e)}}else if(2===arguments.length){var n=arguments[0],i=arguments[1];this.init(n.x,i.x,n.y,i.y)}else if(4===arguments.length){var r=arguments[0],s=arguments[1],o=arguments[2],a=arguments[3];this.init(r,s,o,a)}}function S(){}function w(){S.call(this,"Projective point not representable on the Cartesian plane.")}function L(){}function R(t,e){return t.interfaces_&&t.interfaces_().indexOf(e)>-1}function T(){}function P(t){this.str=t}function b(t){this.value=t}function O(){}function _(){if(this.hi=0,this.lo=0,0===arguments.length)this.init(0);else if(1===arguments.length){if("number"==typeof arguments[0]){var t=arguments[0];this.init(t)}else if(arguments[0]instanceof _){var e=arguments[0];this.init(e)}else if("string"==typeof arguments[0]){var n=arguments[0];_.call(this,_.parse(n))}}else if(2===arguments.length){var i=arguments[0],r=arguments[1];this.init(i,r)}}function M(){}function D(){}function A(){}function F(){if(this.x=null,this.y=null,this.w=null,0===arguments.length)this.x=0,this.y=0,this.w=1;else if(1===arguments.length){var t=arguments[0];this.x=t.x,this.y=t.y,this.w=1}else if(2===arguments.length){if("number"==typeof arguments[0]&&"number"==typeof arguments[1]){var e=arguments[0],n=arguments[1];this.x=e,this.y=n,this.w=1}else if(arguments[0]instanceof F&&arguments[1]instanceof F){var i=arguments[0],r=arguments[1];this.x=i.y*r.w-r.y*i.w,this.y=r.x*i.w-i.x*r.w,this.w=i.x*r.y-r.x*i.y}else if(arguments[0]instanceof g&&arguments[1]instanceof g){var s=arguments[0],o=arguments[1];this.x=s.y-o.y,this.y=o.x-s.x,this.w=s.x*o.y-o.x*s.y}}else if(3===arguments.length){var a=arguments[0],u=arguments[1],l=arguments[2];this.x=a,this.y=u,this.w=l}else if(4===arguments.length){var h=arguments[0],c=arguments[1],f=arguments[2],d=arguments[3],p=h.y-c.y,v=c.x-h.x,m=h.x*c.y-c.x*h.y,y=f.y-d.y,x=d.x-f.x,E=f.x*d.y-d.x*f.y;this.x=v*E-x*m,this.y=y*m-p*E,this.w=p*x-y*v}}function G(){}function q(){}function B(){this.envelope=null,this.factory=null,this.SRID=null,this.userData=null;var t=arguments[0];this.factory=t,this.SRID=t.getSRID()}function z(){}function V(){}function k(){}function Y(){}function U(){}function X(){}function H(){}function W(){}function j(){}function K(){}function Z(){}function Q(){}function J(){this.array_=[],arguments[0]instanceof v&&this.addAll(arguments[0])}function $(t){return null==t?$s:t.color}function tt(t){return null==t?null:t.parent}function et(t,e){null!==t&&(t.color=e)}function nt(t){return null==t?null:t.left}function it(t){return null==t?null:t.right}function rt(){this.root_=null,this.size_=0}function st(){}function ot(){}function at(){this.array_=[],arguments[0]instanceof v&&this.addAll(arguments[0])}function ut(){}function lt(){}function ht(){}function ct(){}function ft(){this.geometries=null;var t=arguments[0],e=arguments[1];if(B.call(this,e),null===t&&(t=[]),B.hasNullElements(t))throw new i("geometries must not contain null elements");this.geometries=t}function gt(){var t=arguments[0],e=arguments[1];ft.call(this,t,e)}function dt(){if(this.geom=null,this.geomFact=null,this.bnRule=null,this.endpointMap=null,1===arguments.length){var t=arguments[0];dt.call(this,t,V.MOD2_BOUNDARY_RULE)}else if(2===arguments.length){var e=arguments[0],n=arguments[1];this.geom=e,this.geomFact=e.getFactory(),this.bnRule=n}}function pt(){this.count=null}function vt(){}function mt(){}function yt(){}function xt(){}function Et(){}function It(){}function Nt(){}function Ct(){}function St(){this.points=null;var t=arguments[0],e=arguments[1];B.call(this,e),this.init(t)}function wt(){}function Lt(){this.coordinates=null;var t=arguments[0],e=arguments[1];B.call(this,e),this.init(t)}function Rt(){}function Tt(){this.shell=null,this.holes=null;var t=arguments[0],e=arguments[1],n=arguments[2];if(B.call(this,n),null===t&&(t=this.getFactory().createLinearRing()),null===e&&(e=[]),B.hasNullElements(e))throw new i("holes must not contain null elements");if(t.isEmpty()&&B.hasNonEmptyElements(e))throw new i("shell is empty but holes are not");this.shell=t,this.holes=e}function Pt(){var t=arguments[0],e=arguments[1];ft.call(this,t,e)}function bt(){if(arguments[0]instanceof g&&arguments[1]instanceof ie){var t=arguments[0],e=arguments[1];bt.call(this,e.getCoordinateSequenceFactory().create(t),e)}else if(R(arguments[0],D)&&arguments[1]instanceof ie){var n=arguments[0],i=arguments[1];St.call(this,n,i),this.validateConstruction()}}function Ot(){var t=arguments[0],e=arguments[1];ft.call(this,t,e)}function _t(){if(this.factory=null,this.isUserDataCopied=!1,0===arguments.length);else if(1===arguments.length){var t=arguments[0];this.factory=t}}function Mt(){}function Dt(){}function At(){}function Ft(){}function Gt(){if(this.dimension=3,this.coordinates=null,1===arguments.length){if(arguments[0]instanceof Array){var t=arguments[0];Gt.call(this,t,3)}else if(Number.isInteger(arguments[0])){var e=arguments[0];this.coordinates=new Array(e).fill(null);for(var n=0;e>n;n++)this.coordinates[n]=new g}else if(R(arguments[0],D)){var i=arguments[0];if(null===i)return this.coordinates=new Array(0).fill(null),null;this.dimension=i.getDimension(),this.coordinates=new Array(i.size()).fill(null);for(var n=0;nn;n++)this.coordinates[n]=new g}}function qt(){}function Bt(t,e){return t===e||t!==t&&e!==e}function zt(t,e){function n(t){return this&&this.constructor===n?(this._keys=[],this._values=[],this._itp=[],this.objectOnly=e,void(t&&Vt.call(this,t))):new n(t)}return e||io(t,"size",{get:Jt}),t.constructor=n,n.prototype=t,n}function Vt(t){this.add?t.forEach(this.add,this):t.forEach(function(t){this.set(t[0],t[1])},this)}function kt(t){return this.has(t)&&(this._keys.splice(no,1),this._values.splice(no,1),this._itp.forEach(function(t){no-1}function Yt(t){return this.has(t)?this._values[no]:void 0}function Ut(t,e){if(this.objectOnly&&e!==Object(e))throw new TypeError("Invalid value used as weak collection key");if(e!==e||0===e)for(no=t.length;no--&&!Bt(t[no],e););else no=t.indexOf(e);return no>-1}function Xt(t){return Ut.call(this,this._keys,t)}function Ht(t,e){return this.has(t)?this._values[no]=e:this._values[this._keys.push(t)-1]=e,this}function Wt(){(this._keys||0).length=this._values.length=0}function jt(){return Qt(this._itp,this._keys)}function Kt(){return Qt(this._itp,this._values)}function Zt(){return Qt(this._itp,this._keys,this._values)}function Qt(t,e,n){var i=[0],r=!1;return t.push(i),{next:function(){var s,o=i[0];return!r&&o1,"Node capacity must be greater than 1"),this.nodeCapacity=t}}function ze(){}function Ve(){}function ke(){if(0===arguments.length)ke.call(this,ke.DEFAULT_NODE_CAPACITY);else if(1===arguments.length){var t=arguments[0];Be.call(this,t)}}function Ye(){var t=arguments[0];Ge.call(this,t)}function Ue(){}function Xe(){this.segString=null,this.coord=null,this.segmentIndex=null,this.segmentOctant=null,this._isInterior=null;var t=arguments[0],e=arguments[1],n=arguments[2],i=arguments[3];this.segString=t,this.coord=new g(e),this.segmentIndex=n,this.segmentOctant=i,this._isInterior=!e.equals2D(t.getCoordinate(n))}function He(){this.nodeMap=new rt,this.edge=null;var t=arguments[0];this.edge=t}function We(){this.nodeList=null,this.edge=null,this.nodeIt=null,this.currNode=null,this.nextNode=null,this.currSegIndex=0;var t=arguments[0];this.nodeList=t,this.edge=t.getEdge(),this.nodeIt=t.iterator(),this.readNextNode()}function je(){}function Ke(){this.nodeList=new He(this),this.pts=null,this.data=null;var t=arguments[0],e=arguments[1];this.pts=t,this.data=e}function Ze(){this.tempEnv1=new C,this.tempEnv2=new C,this.overlapSeg1=new ce,this.overlapSeg2=new ce}function Qe(){this.pts=null,this.start=null,this.end=null,this.env=null,this.context=null,this.id=null;var t=arguments[0],e=arguments[1],n=arguments[2],i=arguments[3];this.pts=t,this.start=e,this.end=n,this.context=i}function Je(){}function $e(){}function tn(){}function en(){if(this.segInt=null,0===arguments.length);else if(1===arguments.length){var t=arguments[0];this.setSegmentIntersector(t)}}function nn(){if(this.monoChains=new I,this.index=new ke,this.idCounter=0,this.nodedSegStrings=null,this.nOverlaps=0,0===arguments.length);else if(1===arguments.length){var t=arguments[0];en.call(this,t)}}function rn(){Ze.apply(this),this.si=null;var t=arguments[0];this.si=t}function sn(){if(this.pt=null,1===arguments.length){var t=arguments[0];l.call(this,t)}else if(2===arguments.length){var e=arguments[0],n=arguments[1];l.call(this,sn.msgWithCoord(e,n)),this.name="TopologyException",this.pt=new g(n)}}function on(){}function an(){this.findAllIntersections=!1,this.isCheckEndSegmentsOnly=!1,this.li=null,this.interiorIntersection=null,this.intSegments=null,this.intersections=new I,this.intersectionCount=0,this.keepIntersections=!0;var t=arguments[0];this.li=t,this.interiorIntersection=null}function un(){this.li=new ae,this.segStrings=null,this.findAllIntersections=!1,this.segInt=null,this._isValid=!0;var t=arguments[0];this.segStrings=t}function ln(){this.nv=null;var t=arguments[0];this.nv=new un(ln.toSegmentStrings(t))}function hn(){this.mapOp=null;var t=arguments[0];this.mapOp=t}function cn(){}function fn(){if(this.location=null,1===arguments.length){if(arguments[0]instanceof Array){var t=arguments[0];this.init(t.length)}else if(Number.isInteger(arguments[0])){var e=arguments[0];this.init(1),this.location[cn.ON]=e}else if(arguments[0]instanceof fn){var n=arguments[0];if(this.init(n.location.length),null!==n)for(var i=0;it;t++)for(var e=0;3>e;e++)this.depth[t][e]=Qn.NULL_VALUE}function Jn(){if(mn.apply(this),this.pts=null,this.env=null,this.eiList=new jn(this),this.name=null,this.mce=null,this._isIsolated=!0,this.depth=new Qn,this.depthDelta=0,1===arguments.length){var t=arguments[0];Jn.call(this,t,null)}else if(2===arguments.length){var e=arguments[0],n=arguments[1];this.pts=e,this.label=n}}function $n(){if(Cn.apply(this),this.parentGeom=null,this.lineEdgeMap=new te,this.boundaryNodeRule=null,this.useBoundaryDeterminationRule=!0,this.argIndex=null,this.boundaryNodes=null,this._hasTooFewPoints=!1,this.invalidPoint=null,this.areaPtLocator=null,this.ptLocator=new Te,2===arguments.length){var t=arguments[0],e=arguments[1];$n.call(this,t,e,V.OGC_SFS_BOUNDARY_RULE)}else if(3===arguments.length){var n=arguments[0],i=arguments[1],r=arguments[2];this.argIndex=n,this.parentGeom=i,this.boundaryNodeRule=r,null!==i&&this.add(i)}}function ti(){if(this.li=new ae,this.resultPrecisionModel=null,this.arg=null,1===arguments.length){var t=arguments[0];this.setComputationPrecision(t.getPrecisionModel()),this.arg=new Array(1).fill(null),this.arg[0]=new $n(0,t)}else if(2===arguments.length){var e=arguments[0],n=arguments[1];ti.call(this,e,n,V.OGC_SFS_BOUNDARY_RULE)}else if(3===arguments.length){var i=arguments[0],r=arguments[1],s=arguments[2];i.getPrecisionModel().compareTo(r.getPrecisionModel())>=0?this.setComputationPrecision(i.getPrecisionModel()):this.setComputationPrecision(r.getPrecisionModel()),this.arg=new Array(2).fill(null),this.arg[0]=new $n(0,i,s),this.arg[1]=new $n(1,r,s)}}function ei(){this.pts=null,this._orientation=null;var t=arguments[0];this.pts=t,this._orientation=ei.orientation(t)}function ni(){this.edges=new I,this.ocaMap=new rt}function ii(){this.ptLocator=new Te,this.geomFact=null,this.resultGeom=null,this.graph=null,this.edgeList=new ni,this.resultPolyList=new I,this.resultLineList=new I,this.resultPointList=new I;var t=arguments[0],e=arguments[1];ti.call(this,t,e),this.graph=new Cn(new On),this.geomFact=t.getFactory()}function ri(){this.geom=new Array(2).fill(null),this.snapTolerance=null,this.cbr=null;var t=arguments[0],e=arguments[1];this.geom[0]=t,this.geom[1]=e,this.computeSnapTolerance()}function si(){this.geom=new Array(2).fill(null);var t=arguments[0],e=arguments[1];this.geom[0]=t,this.geom[1]=e}function oi(){this.factory=null,this.interiorPoint=null,this.maxWidth=0;var t=arguments[0];this.factory=t.getFactory(),this.add(t)}function ai(){this.poly=null,this.centreY=null,this.hiY=r.MAX_VALUE,this.loY=-r.MAX_VALUE;var t=arguments[0];this.poly=t,this.hiY=t.getEnvelopeInternal().getMaxY(),this.loY=t.getEnvelopeInternal().getMinY(),this.centreY=oi.avg(this.loY,this.hiY)}function ui(){this.centroid=null,this.minDistance=r.MAX_VALUE,this.interiorPoint=null;var t=arguments[0];this.centroid=t.getCentroid().getCoordinate(),this.addInterior(t),null===this.interiorPoint&&this.addEndpoints(t)}function li(){this.centroid=null,this.minDistance=r.MAX_VALUE,this.interiorPoint=null;var t=arguments[0];this.centroid=t.getCentroid().getCoordinate(),this.add(t)}function hi(){this.tempEnv1=new C,this.selectedSegment=new ce}function ci(){this.items=new I,this.subnode=[null,null]}function fi(){if(this.min=null,this.max=null,0===arguments.length)this.min=0,this.max=0;else if(1===arguments.length){var t=arguments[0];this.init(t.min,t.max)}else if(2===arguments.length){var e=arguments[0],n=arguments[1];this.init(e,n)}}function gi(){}function di(t,e){var n,i,r,s,o={32:{d:127,c:128,b:0,a:0},64:{d:32752,c:0,b:0,a:0}},a={32:8,64:11}[t];if(s||(n=0>e||0>1/e,isFinite(e)||(s=o[t],n&&(s.d+=1<=2;)i++,r/=2;for(;1>r&&i>0;)i--,r*=2;0>=i&&(r/=2),32===t&&i>254&&(s={d:n?255:127,c:128,b:0,a:0},i=Math.pow(2,a)-1,r=0)}return i}function pi(){this.pt=0,this.level=0,this.interval=null;var t=arguments[0];this.computeKey(t)}function vi(){ci.apply(this),this.interval=null,this.centre=null,this.level=null;var t=arguments[0],e=arguments[1];this.interval=t,this.level=e,this.centre=(t.getMin()+t.getMax())/2}function mi(){}function yi(){ci.apply(this)}function xi(){this.root=null,this.minExtent=1,this.root=new yi}function Ei(){}function Ii(){this.ring=null,this.tree=null,this.crossings=0,this.interval=new fi;var t=arguments[0];this.ring=t,this.buildIndex()}function Ni(){hi.apply(this),this.mcp=null,this.p=null;var t=arguments[0],e=arguments[1];this.mcp=t,this.p=e}function Ci(){}function Si(){this.p0=null,this.p1=null,this.p2=null;var t=arguments[0],e=arguments[1],n=arguments[2];this.p0=t,this.p1=e,this.p2=n}function wi(){this.input=null,this.extremalPts=null,this.centre=null,this.radius=0;var t=arguments[0];this.input=t}function Li(){if(this.inputGeom=null,this.isConvex=null,this.convexHullPts=null,this.minBaseSeg=new ce,this.minWidthPt=null,this.minPtIndex=null,this.minWidth=0,1===arguments.length){var t=arguments[0];Li.call(this,t,!1)}else if(2===arguments.length){var e=arguments[0],n=arguments[1];this.inputGeom=e,this.isConvex=n}}function Ri(){this.inputGeom=null,this.distanceTolerance=null;var t=arguments[0];this.inputGeom=t}function Ti(){xe.apply(this),this.distanceTolerance=null;var t=arguments[0];this.distanceTolerance=t}function Pi(){this._orig=null,this._sym=null,this._next=null;var t=arguments[0];this._orig=t}function bi(){this._isMarked=!1;var t=arguments[0];Pi.call(this,t)}function Oi(){this.vertexMap=new te}function _i(){this._isStart=!1;var t=arguments[0];bi.call(this,t)}function Mi(){Oi.apply(this)}function Di(){this.result=null,this.factory=null,this.graph=null,this.lines=new I,this.nodeEdgeStack=new pe,this.ringStartEdge=null,this.graph=new Mi}function Ai(){this.items=new I,this.subnode=new Array(4).fill(null)}function Fi(){this.pt=new g,this.level=0,this.env=null;var t=arguments[0];this.computeKey(t)}function Gi(){Ai.apply(this),this.env=null,this.centrex=null,this.centrey=null,this.level=null;var t=arguments[0],e=arguments[1];this.env=t,this.level=e,this.centrex=(t.getMinX()+t.getMaxX())/2,this.centrey=(t.getMinY()+t.getMaxY())/2}function qi(){Ai.apply(this)}function Bi(){this.root=null,this.minExtent=1,this.root=new qi}function zi(t){this.geometryFactory=t||new ie}function Vi(t){this.geometryFactory=t||new ie,this.precisionModel=this.geometryFactory.getPrecisionModel(),this.parser=new zi(this.geometryFactory)}function ki(){this.parser=new zi(this.geometryFactory)}function Yi(t){this.geometryFactory=t||new ie,this.precisionModel=this.geometryFactory.getPrecisionModel(),this.parser=new re(this.geometryFactory)}function Ui(t){return[t.x,t.y]}function Xi(t){this.geometryFactory=t||new ie}function Hi(){if(this.noder=null,this.scaleFactor=null,this.offsetX=null,this.offsetY=null,this.isScaled=!1,2===arguments.length){var t=arguments[0],e=arguments[1];Hi.call(this,t,e,0,0)}else if(4===arguments.length){var n=arguments[0],i=arguments[1];arguments[2],arguments[3];this.noder=n,this.scaleFactor=i,this.isScaled=!this.isIntegerPrecision()}}function Wi(){if(this.inputGeom=null,this.isClosedEndpointsInInterior=!0,this.nonSimpleLocation=null,1===arguments.length){var t=arguments[0];this.inputGeom=t}else if(2===arguments.length){var e=arguments[0],n=arguments[1];this.inputGeom=e, +this.isClosedEndpointsInInterior=!n.isInBoundary(2)}}function ji(){this.pt=null,this.isClosed=null,this.degree=null;var t=arguments[0];this.pt=t,this.isClosed=!1,this.degree=0}function Ki(){if(this.quadrantSegments=Ki.DEFAULT_QUADRANT_SEGMENTS,this.endCapStyle=Ki.CAP_ROUND,this.joinStyle=Ki.JOIN_ROUND,this.mitreLimit=Ki.DEFAULT_MITRE_LIMIT,this._isSingleSided=!1,this.simplifyFactor=Ki.DEFAULT_SIMPLIFY_FACTOR,0===arguments.length);else if(1===arguments.length){var t=arguments[0];this.setQuadrantSegments(t)}else if(2===arguments.length){var e=arguments[0],n=arguments[1];this.setQuadrantSegments(e),this.setEndCapStyle(n)}else if(4===arguments.length){var i=arguments[0],r=arguments[1],s=arguments[2],o=arguments[3];this.setQuadrantSegments(i),this.setEndCapStyle(r),this.setJoinStyle(s),this.setMitreLimit(o)}}function Zi(){this.minIndex=-1,this.minCoord=null,this.minDe=null,this.orientedDe=null}function Qi(){this.array_=[]}function Ji(){this.finder=null,this.dirEdgeList=new I,this.nodes=new I,this.rightMostCoord=null,this.env=null,this.finder=new Zi}function $i(){this.inputLine=null,this.distanceTol=null,this.isDeleted=null,this.angleOrientation=he.COUNTERCLOCKWISE;var t=arguments[0];this.inputLine=t}function tr(){this.ptList=null,this.precisionModel=null,this.minimimVertexDistance=0,this.ptList=new I}function er(){this.maxCurveSegmentError=0,this.filletAngleQuantum=null,this.closingSegLengthFactor=1,this.segList=null,this.distance=0,this.precisionModel=null,this.bufParams=null,this.li=null,this.s0=null,this.s1=null,this.s2=null,this.seg0=new ce,this.seg1=new ce,this.offset0=new ce,this.offset1=new ce,this.side=0,this._hasNarrowConcaveAngle=!1;var t=arguments[0],e=arguments[1],n=arguments[2];this.precisionModel=t,this.bufParams=e,this.li=new ae,this.filletAngleQuantum=Math.PI/2/e.getQuadrantSegments(),e.getQuadrantSegments()>=8&&e.getJoinStyle()===Ki.JOIN_ROUND&&(this.closingSegLengthFactor=er.MAX_CLOSING_SEG_LEN_FACTOR),this.init(n)}function nr(){this.distance=0,this.precisionModel=null,this.bufParams=null;var t=arguments[0],e=arguments[1];this.precisionModel=t,this.bufParams=e}function ir(){this.subgraphs=null,this.seg=new ce,this.cga=new he;var t=arguments[0];this.subgraphs=t}function rr(){this.upwardSeg=null,this.leftDepth=null;var t=arguments[0],e=arguments[1];this.upwardSeg=new ce(t),this.leftDepth=e}function sr(){this.inputGeom=null,this.distance=null,this.curveBuilder=null,this.curveList=new I;var t=arguments[0],e=arguments[1],n=arguments[2];this.inputGeom=t,this.distance=e,this.curveBuilder=n}function or(){this._hasIntersection=!1,this.hasProper=!1,this.hasProperInterior=!1,this.hasInterior=!1,this.properIntersectionPoint=null,this.li=null,this.isSelfIntersection=null,this.numIntersections=0,this.numInteriorIntersections=0,this.numProperIntersections=0,this.numTests=0;var t=arguments[0];this.li=t}function ar(){this.bufParams=null,this.workingPrecisionModel=null,this.workingNoder=null,this.geomFact=null,this.graph=null,this.edgeList=new ni;var t=arguments[0];this.bufParams=t}function ur(){this.li=new ae,this.segStrings=null;var t=arguments[0];this.segStrings=t}function lr(){this.li=null,this.pt=null,this.originalPt=null,this.ptScaled=null,this.p0Scaled=null,this.p1Scaled=null,this.scaleFactor=null,this.minx=null,this.maxx=null,this.miny=null,this.maxy=null,this.corner=new Array(4).fill(null),this.safeEnv=null;var t=arguments[0],e=arguments[1],n=arguments[2];if(this.originalPt=t,this.pt=t,this.scaleFactor=e,this.li=n,0>=e)throw new i("Scale factor must be non-zero");1!==e&&(this.pt=new g(this.scale(t.x),this.scale(t.y)),this.p0Scaled=new g,this.p1Scaled=new g),this.initCorners(this.pt)}function hr(){this.index=null;var t=arguments[0];this.index=t}function cr(){hi.apply(this),this.hotPixel=null,this.parentEdge=null,this.hotPixelVertexIndex=null,this._isNodeAdded=!1;var t=arguments[0],e=arguments[1],n=arguments[2];this.hotPixel=t,this.parentEdge=e,this.hotPixelVertexIndex=n}function fr(){this.li=null,this.interiorIntersections=null;var t=arguments[0];this.li=t,this.interiorIntersections=new I}function gr(){this.pm=null,this.li=null,this.scaleFactor=null,this.noder=null,this.pointSnapper=null,this.nodedSegStrings=null;var t=arguments[0];this.pm=t,this.li=new ae,this.li.setPrecisionModel(t),this.scaleFactor=t.getScale()}function dr(){if(this.argGeom=null,this.distance=null,this.bufParams=new Ki,this.resultGeometry=null,this.saveException=null,1===arguments.length){var t=arguments[0];this.argGeom=t}else if(2===arguments.length){var e=arguments[0],n=arguments[1];this.argGeom=e,this.bufParams=n}}function pr(){this.comps=null;var t=arguments[0];this.comps=t}function vr(){if(this.component=null,this.segIndex=null,this.pt=null,2===arguments.length){var t=arguments[0],e=arguments[1];vr.call(this,t,vr.INSIDE_AREA,e)}else if(3===arguments.length){var n=arguments[0],i=arguments[1],r=arguments[2];this.component=n,this.segIndex=i,this.pt=r}}function mr(){this.pts=null;var t=arguments[0];this.pts=t}function yr(){this.locations=null;var t=arguments[0];this.locations=t}function xr(){if(this.geom=null,this.terminateDistance=0,this.ptLocator=new Te,this.minDistanceLocation=null,this.minDistance=r.MAX_VALUE,2===arguments.length){var t=arguments[0],e=arguments[1];xr.call(this,t,e,0)}else if(3===arguments.length){var n=arguments[0],i=arguments[1],s=arguments[2];this.geom=new Array(2).fill(null),this.geom[0]=n,this.geom[1]=i,this.terminateDistance=s}}function Er(){this.factory=null,this.directedEdges=new I,this.coordinates=null;var t=arguments[0];this.factory=t}function Ir(){this._isMarked=!1,this._isVisited=!1,this.data=null}function Nr(){Ir.apply(this),this.parentEdge=null,this.from=null,this.to=null,this.p0=null,this.p1=null,this.sym=null,this.edgeDirection=null,this.quadrant=null,this.angle=null;var t=arguments[0],e=arguments[1],n=arguments[2],i=arguments[3];this.from=t,this.to=e,this.edgeDirection=i,this.p0=t.getCoordinate(),this.p1=n;var r=this.p1.x-this.p0.x,s=this.p1.y-this.p0.y;this.quadrant=Je.quadrant(r,s),this.angle=Math.atan2(s,r)}function Cr(){var t=arguments[0],e=arguments[1],n=arguments[2],i=arguments[3];Nr.call(this,t,e,n,i)}function Sr(){if(Ir.apply(this),this.dirEdge=null,0===arguments.length);else if(2===arguments.length){var t=arguments[0],e=arguments[1];this.setDirectedEdges(t,e)}}function wr(){this.outEdges=new I,this.sorted=!1}function Lr(){if(Ir.apply(this),this.pt=null,this.deStar=null,1===arguments.length){var t=arguments[0];Lr.call(this,t,new wr)}else if(2===arguments.length){var e=arguments[0],n=arguments[1];this.pt=e,this.deStar=n}}function Rr(){Sr.apply(this),this.line=null;var t=arguments[0];this.line=t}function Tr(){this.nodeMap=new rt}function Pr(){this.edges=new J,this.dirEdges=new J,this.nodeMap=new Tr}function br(){Pr.apply(this)}function Or(){this.graph=new br,this.mergedLineStrings=null,this.factory=null,this.edgeStrings=null}function _r(){this.edgeRing=null,this.next=null,this.label=-1;var t=arguments[0],e=arguments[1],n=arguments[2],i=arguments[3];Nr.call(this,t,e,n,i)}function Mr(){Sr.apply(this),this.line=null;var t=arguments[0];this.line=t}function Dr(){this.factory=null,this.deList=new I,this.lowestEdge=null,this.ring=null,this.ringPts=null,this.holes=null,this.shell=null,this._isHole=null,this._isProcessed=!1,this._isIncludedSet=!1,this._isIncluded=!1;var t=arguments[0];this.factory=t}function Ar(){}function Fr(){Pr.apply(this),this.factory=null;var t=arguments[0];this.factory=t}function Gr(){if(this.lineStringAdder=new qr(this),this.graph=null,this.dangles=new I,this.cutEdges=new I,this.invalidRingLines=new I,this.holeList=null,this.shellList=null,this.polyList=null,this.isCheckingRingsValid=!0,this.extractOnlyPolygonal=null,this.geomFactory=null,0===arguments.length)Gr.call(this,!1);else if(1===arguments.length){var t=arguments[0];this.extractOnlyPolygonal=t}}function qr(){this.p=null;var t=arguments[0];this.p=t}function Br(){}function zr(){if(this.edgeEnds=new I,1===arguments.length){var t=arguments[0];zr.call(this,null,t)}else if(2===arguments.length){var e=(arguments[0],arguments[1]);En.call(this,e.getEdge(),e.getCoordinate(),e.getDirectedCoordinate(),new gn(e.getLabel())),this.insert(e)}}function Vr(){Pn.apply(this)}function kr(){var t=arguments[0],e=arguments[1];yn.call(this,t,e)}function Yr(){Nn.apply(this)}function Ur(){this.li=new ae,this.ptLocator=new Te,this.arg=null,this.nodes=new xn(new Yr),this.im=null,this.isolatedEdges=new I,this.invalidPoint=null;var t=arguments[0];this.arg=t}function Xr(){this.rectEnv=null;var t=arguments[0];this.rectEnv=t.getEnvelopeInternal()}function Hr(){this.li=new ae,this.rectEnv=null,this.diagUp0=null,this.diagUp1=null,this.diagDown0=null,this.diagDown1=null;var t=arguments[0];this.rectEnv=t,this.diagUp0=new g(t.getMinX(),t.getMinY()),this.diagUp1=new g(t.getMaxX(),t.getMaxY()),this.diagDown0=new g(t.getMinX(),t.getMaxY()),this.diagDown1=new g(t.getMaxX(),t.getMinY())}function Wr(){this._isDone=!1}function jr(){this.rectangle=null,this.rectEnv=null;var t=arguments[0];this.rectangle=t,this.rectEnv=t.getEnvelopeInternal()}function Kr(){Wr.apply(this),this.rectEnv=null,this._intersects=!1;var t=arguments[0];this.rectEnv=t}function Zr(){Wr.apply(this),this.rectSeq=null,this.rectEnv=null,this._containsPoint=!1;var t=arguments[0];this.rectSeq=t.getExteriorRing().getCoordinateSequence(),this.rectEnv=t.getEnvelopeInternal()}function Qr(){Wr.apply(this),this.rectEnv=null,this.rectIntersector=null,this.hasIntersection=!1,this.p0=new g,this.p1=new g;var t=arguments[0];this.rectEnv=t.getEnvelopeInternal(),this.rectIntersector=new Hr(this.rectEnv)}function Jr(){if(this._relate=null,2===arguments.length){var t=arguments[0],e=arguments[1];ti.call(this,t,e),this._relate=new Ur(this.arg)}else if(3===arguments.length){var n=arguments[0],i=arguments[1],r=arguments[2];ti.call(this,n,i,r),this._relate=new Ur(this.arg)}}function $r(){this.geomFactory=null,this.skipEmpty=!1,this.inputGeoms=null;var t=arguments[0];this.geomFactory=$r.extractFactory(t),this.inputGeoms=t}function ts(){this.pointGeom=null,this.otherGeom=null,this.geomFact=null;var t=arguments[0],e=arguments[1];this.pointGeom=t,this.otherGeom=e,this.geomFact=e.getFactory()}function es(){this.sortIndex=-1,this.comps=null;var t=arguments[0],e=arguments[1];this.sortIndex=t,this.comps=e}function ns(){this.inputPolys=null,this.geomFactory=null;var t=arguments[0];this.inputPolys=t,null===this.inputPolys&&(this.inputPolys=new I)}function is(){if(this.polygons=new I,this.lines=new I,this.points=new I,this.geomFact=null,1===arguments.length){if(R(arguments[0],v)){var t=arguments[0];this.extract(t)}else if(arguments[0]instanceof B){var e=arguments[0];this.extract(e)}}else if(2===arguments.length){var n=arguments[0],i=arguments[1];this.geomFact=i,this.extract(n)}}function rs(){this.geometryFactory=new ie,this.geomGraph=null,this.disconnectedRingcoord=null;var t=arguments[0];this.geomGraph=t}function ss(){this.nodes=new xn(new Yr)}function os(){this.li=new ae,this.geomGraph=null,this.nodeGraph=new ss,this.invalidPoint=null;var t=arguments[0];this.geomGraph=t}function as(){this.graph=null,this.rings=new I,this.totalEnv=new C,this.index=null,this.nestedPt=null;var t=arguments[0];this.graph=t}function us(){if(this.errorType=null,this.pt=null,1===arguments.length){var t=arguments[0];us.call(this,t,null)}else if(2===arguments.length){var e=arguments[0],n=arguments[1];this.errorType=e,null!==n&&(this.pt=n.copy())}}function ls(){this.parentGeometry=null,this.isSelfTouchingRingFormingHoleValid=!1,this.validErr=null;var t=arguments[0];this.parentGeometry=t}function hs(){_t.CoordinateOperation.apply(this),this.targetPM=null,this.removeCollapsed=!0;var t=arguments[0],e=arguments[1];this.targetPM=t,this.removeCollapsed=e}function cs(){this.targetPM=null,this.removeCollapsed=!0,this.changePrecisionModel=!1,this.isPointwise=!1;var t=arguments[0];this.targetPM=t}function fs(){this.pts=null,this.usePt=null,this.distanceTolerance=null,this.seg=new ce;var t=arguments[0];this.pts=t}function gs(){this.inputGeom=null,this.distanceTolerance=null,this.isEnsureValidTopology=!0;var t=arguments[0];this.inputGeom=t}function ds(){xe.apply(this),this.isEnsureValidTopology=!0,this.distanceTolerance=null;var t=arguments[0],e=arguments[1];this.isEnsureValidTopology=t,this.distanceTolerance=e}function ps(){if(this.parent=null,this.index=null,2===arguments.length){var t=arguments[0],e=arguments[1];ps.call(this,t,e,null,-1)}else if(4===arguments.length){var n=arguments[0],i=arguments[1],r=arguments[2],s=arguments[3];ce.call(this,n,i),this.parent=r,this.index=s}}function vs(){if(this.parentLine=null,this.segs=null,this.resultSegs=new I,this.minimumSize=null,1===arguments.length){var t=arguments[0];vs.call(this,t,2)}else if(2===arguments.length){var e=arguments[0],n=arguments[1];this.parentLine=e,this.minimumSize=n,this.init()}}function ms(){this.index=new Bi}function ys(){this.querySeg=null,this.items=new I;var t=arguments[0];this.querySeg=t}function xs(){this.li=new ae,this.inputIndex=new ms,this.outputIndex=new ms,this.line=null,this.linePts=null,this.distanceTolerance=0;var t=arguments[0],e=arguments[1];this.inputIndex=t,this.outputIndex=e}function Es(){this.inputIndex=new ms,this.outputIndex=new ms,this.distanceTolerance=0}function Is(){this.inputGeom=null,this.lineSimplifier=new Es,this.linestringMap=null;var t=arguments[0];this.inputGeom=t}function Ns(){xe.apply(this),this.linestringMap=null;var t=arguments[0];this.linestringMap=t}function Cs(){this.tps=null;var t=arguments[0];this.tps=t}function Ss(){this.seg=null,this.segLen=null,this.splitPt=null,this.minimumLen=0;var t=arguments[0];this.seg=t,this.segLen=t.getLength()}function ws(){}function Ls(){}function Rs(){}function Ts(){if(this.p=null,1===arguments.length){var t=arguments[0];this.p=new g(t)}else if(2===arguments.length){var e=arguments[0],n=arguments[1];this.p=new g(e,n)}else if(3===arguments.length){var i=arguments[0],r=arguments[1],s=arguments[2];this.p=new g(i,r,s)}}function Ps(){this._isOnConstraint=null,this.constraint=null;var t=arguments[0];Ts.call(this,t)}function bs(){this._rot=null,this.vertex=null,this.next=null,this.data=null}function Os(){this.subdiv=null,this.isUsingTolerance=!1;var t=arguments[0];this.subdiv=t,this.isUsingTolerance=t.getTolerance()>0}function _s(){}function Ms(){this.subdiv=null,this.lastEdge=null;var t=arguments[0];this.subdiv=t,this.init()}function Ds(){if(this.seg=null,1===arguments.length){if("string"==typeof arguments[0]){var t=arguments[0];l.call(this,t)}else if(arguments[0]instanceof ce){var e=arguments[0];l.call(this,"Locate failed to converge (at edge: "+e+"). Possible causes include invalid Subdivision topology or very close sites"),this.seg=new ce(e)}}else if(2===arguments.length){var n=arguments[0],i=arguments[1];l.call(this,Ds.msgWithSpatial(n,i)),this.seg=new ce(i)}}function As(){}function Fs(){this.visitedKey=0,this.quadEdges=new I,this.startingEdge=null,this.tolerance=null,this.edgeCoincidenceTolerance=null,this.frameVertex=new Array(3).fill(null),this.frameEnv=null,this.locator=null,this.seg=new ce,this.triEdges=new Array(3).fill(null);var t=arguments[0],e=arguments[1];this.tolerance=e,this.edgeCoincidenceTolerance=e/Fs.EDGE_COINCIDENCE_TOL_FACTOR,this.createFrame(t),this.startingEdge=this.initSubdiv(),this.locator=new Ms(this)}function Gs(){}function qs(){this.triList=new I}function Bs(){this.triList=new I}function zs(){this.coordList=new N,this.triCoords=new I}function Vs(){if(this.ls=null,this.data=null,2===arguments.length){var t=arguments[0],e=arguments[1];this.ls=new ce(t,e)}else if(3===arguments.length){var n=arguments[0],i=arguments[1],r=arguments[2];this.ls=new ce(n,i),this.data=r}else if(6===arguments.length){var s=arguments[0],o=arguments[1],a=arguments[2],u=arguments[3],l=arguments[4],h=arguments[5];Vs.call(this,new g(s,o,a),new g(u,l,h))}else if(7===arguments.length){var c=arguments[0],f=arguments[1],d=arguments[2],p=arguments[3],v=arguments[4],m=arguments[5],y=arguments[6];Vs.call(this,new g(c,f,d),new g(p,v,m),y)}}function ks(){}function Ys(){if(this.p=null,this.data=null,this.left=null,this.right=null,this.count=null,2===arguments.length){var t=arguments[0],e=arguments[1];this.p=new g(t),this.left=null,this.right=null,this.count=1,this.data=e}else if(3===arguments.length){var n=arguments[0],i=arguments[1],r=arguments[2];this.p=new g(n,i),this.left=null,this.right=null,this.count=1,this.data=r}}function Us(){if(this.root=null,this.numberOfNodes=null,this.tolerance=null,0===arguments.length)Us.call(this,0);else if(1===arguments.length){var t=arguments[0];this.tolerance=t}}function Xs(){this.tolerance=null,this.matchNode=null,this.matchDist=0,this.p=null;var t=arguments[0],e=arguments[1];this.p=t,this.tolerance=e}function Hs(){this.initialVertices=null,this.segVertices=null,this.segments=new I,this.subdiv=null,this.incDel=null,this.convexHull=null,this.splitFinder=new Ls,this.kdt=null,this.vertexFactory=null,this.computeAreaEnv=null,this.splitPt=null,this.tolerance=null;var t=arguments[0],e=arguments[1];this.initialVertices=new I(t),this.tolerance=e,this.kdt=new Us(e)}function Ws(){this.siteCoords=null,this.tolerance=0,this.subdiv=null}function js(){this.siteCoords=null,this.constraintLines=null,this.tolerance=0,this.subdiv=null,this.constraintVertexMap=new rt}function Ks(){this.siteCoords=null,this.tolerance=0,this.subdiv=null,this.clipEnv=null,this.diagramEnv=null}function Zs(){}Array.prototype.fill||(Array.prototype.fill=function(t){for(var e=Object(this),n=parseInt(e.length,10),i=arguments[1],r=parseInt(i,10)||0,s=0>r?Math.max(n+r,0):Math.min(r,n),o=arguments[2],a=void 0===o?n:parseInt(o,10)||0,u=0>a?Math.max(n+a,0):Math.min(a,n);u>s;s++)e[s]=t;return e}),Number.isFinite=Number.isFinite||function(t){return"number"==typeof t&&isFinite(t)},Number.isInteger=Number.isInteger||function(t){return"number"==typeof t&&isFinite(t)&&Math.floor(t)===t},Number.parseFloat=Number.parseFloat||parseFloat,Number.isNaN=Number.isNaN||function(t){return t!==t},Math.trunc=Math.trunc||function(t){return 0>t?Math.ceil(t):Math.floor(t)},e(n.prototype,{interfaces_:function(){return[]},getClass:function(){return n}}),n.equalsWithTolerance=function(t,e,n){return Math.abs(t-e)<=n},r.isNaN=function(t){return Number.isNaN(t)},r.doubleToLongBits=function(t){return t},r.longBitsToDouble=function(t){return t},r.isInfinite=function(t){return!Number.isFinite(t)},r.MAX_VALUE=Number.MAX_VALUE,l.prototype=Object.create(Error.prototype),l.prototype.constructor=Error,h(c,l),e(c.prototype,{interfaces_:function(){return[]},getClass:function(){return c}}),e(f.prototype,{interfaces_:function(){return[]},getClass:function(){return f}}),f.shouldNeverReachHere=function(){if(0===arguments.length)f.shouldNeverReachHere(null);else if(1===arguments.length){var t=arguments[0];throw new c("Should never reach here"+(null!==t?": "+t:""))}},f.isTrue=function(){if(1===arguments.length){var t=arguments[0];f.isTrue(t,null)}else if(2===arguments.length){var e=arguments[0],n=arguments[1];if(!e)throw null===n?new c:new c(n)}},f.equals=function(){if(2===arguments.length){var t=arguments[0],e=arguments[1];f.equals(t,e,null)}else if(3===arguments.length){var n=arguments[0],i=arguments[1],r=arguments[2];if(!i.equals(n))throw new c("Expected "+n+" but encountered "+i+(null!==r?": "+r:""))}},e(g.prototype,{setOrdinate:function(t,e){switch(t){case g.X:this.x=e;break;case g.Y:this.y=e;break;case g.Z:this.z=e;break;default:throw new i("Invalid ordinate index: "+t)}},equals2D:function(){if(1===arguments.length){var t=arguments[0];return this.x!==t.x?!1:this.y===t.y}if(2===arguments.length){var e=arguments[0],i=arguments[1];return n.equalsWithTolerance(this.x,e.x,i)?!!n.equalsWithTolerance(this.y,e.y,i):!1}},getOrdinate:function(t){switch(t){case g.X:return this.x;case g.Y:return this.y;case g.Z:return this.z}throw new i("Invalid ordinate index: "+t)},equals3D:function(t){return this.x===t.x&&this.y===t.y&&(this.z===t.z||r.isNaN(this.z)&&r.isNaN(t.z))},equals:function(t){return t instanceof g?this.equals2D(t):!1},equalInZ:function(t,e){return n.equalsWithTolerance(this.z,t.z,e)},compareTo:function(t){var e=t;return this.xe.x?1:this.ye.y?1:0},clone:function(){try{var t=null;return t}catch(e){if(e instanceof CloneNotSupportedException)return f.shouldNeverReachHere("this shouldn't happen because this class is Cloneable"),null;throw e}finally{}},copy:function(){return new g(this)},toString:function(){return"("+this.x+", "+this.y+", "+this.z+")"},distance3D:function(t){var e=this.x-t.x,n=this.y-t.y,i=this.z-t.z;return Math.sqrt(e*e+n*n+i*i)},distance:function(t){var e=this.x-t.x,n=this.y-t.y;return Math.sqrt(e*e+n*n)},hashCode:function(){var t=17;return t=37*t+g.hashCode(this.x),t=37*t+g.hashCode(this.y)},setCoordinate:function(t){this.x=t.x,this.y=t.y,this.z=t.z},interfaces_:function(){return[s,o,u]},getClass:function(){return g}}),g.hashCode=function(){if(1===arguments.length){var t=arguments[0],e=r.doubleToLongBits(t);return Math.trunc(e^e>>>32)}},e(d.prototype,{compare:function(t,e){var n=t,i=e,r=d.compare(n.x,i.x);if(0!==r)return r;var s=d.compare(n.y,i.y);if(0!==s)return s;if(this.dimensionsToTest<=2)return 0;var o=d.compare(n.z,i.z);return o},interfaces_:function(){return[a]},getClass:function(){return d}}),d.compare=function(t,e){return e>t?-1:t>e?1:r.isNaN(t)?r.isNaN(e)?0:-1:r.isNaN(e)?1:0},g.DimensionalComparator=d,g.serialVersionUID=0x5cbf2c235c7e5800,g.NULL_ORDINATE=r.NaN,g.X=0,g.Y=1,g.Z=2,p.prototype.hasNext=function(){},p.prototype.next=function(){},p.prototype.remove=function(){},v.prototype.add=function(){},v.prototype.addAll=function(){},v.prototype.isEmpty=function(){},v.prototype.iterator=function(){},v.prototype.size=function(){},v.prototype.toArray=function(){},v.prototype.remove=function(){},m.prototype=new Error,m.prototype.name="IndexOutOfBoundsException",y.prototype=Object.create(v.prototype),y.prototype.constructor=y,y.prototype.get=function(){},y.prototype.set=function(){},y.prototype.isEmpty=function(){},x.prototype=new Error,x.prototype.name="NoSuchElementException",E.prototype=new Error,E.prototype.name="OperationNotSupported",I.prototype=Object.create(y.prototype),I.prototype.constructor=I,I.prototype.ensureCapacity=function(){},I.prototype.interfaces_=function(){return[y,v]},I.prototype.add=function(t){return 1===arguments.length?this.array_.push(t):this.array_.splice(arguments[0],arguments[1]),!0},I.prototype.clear=function(){this.array_=[]},I.prototype.addAll=function(t){for(var e=t.iterator();e.hasNext();)this.add(e.next());return!0},I.prototype.set=function(t,e){var n=this.array_[t];return this.array_[t]=e,n},I.prototype.iterator=function(){return new Qs(this)},I.prototype.get=function(t){if(0>t||t>=this.size())throw new m;return this.array_[t]},I.prototype.isEmpty=function(){return 0===this.array_.length},I.prototype.size=function(){return this.array_.length},I.prototype.toArray=function(){for(var t=[],e=0,n=this.array_.length;n>e;e++)t.push(this.array_[e]);return t},I.prototype.remove=function(t){for(var e=!1,n=0,i=this.array_.length;i>n;n++)if(this.array_[n]===t){this.array_.splice(n,1),e=!0;break}return e};var Qs=function(t){this.arrayList_=t,this.position_=0};Qs.prototype.next=function(){if(this.position_===this.arrayList_.size())throw new x;return this.arrayList_.get(this.position_++)},Qs.prototype.hasNext=function(){return this.position_=1){var s=this.get(this.size()-1);if(s.equals2D(i))return null}I.prototype.add.call(this,i)}else if(arguments[0]instanceof Object&&"boolean"==typeof arguments[1]){var o=arguments[0],a=arguments[1];return this.add(o,a),!0}}else if(3===arguments.length){if("boolean"==typeof arguments[2]&&arguments[0]instanceof Array&&"boolean"==typeof arguments[1]){var u=arguments[0],l=arguments[1],h=arguments[2];if(h)for(var c=0;c=0;c--)this.add(u[c],l);return!0}if("boolean"==typeof arguments[2]&&Number.isInteger(arguments[0])&&arguments[1]instanceof g){var f=arguments[0],d=arguments[1],p=arguments[2];if(!p){var v=this.size();if(v>0){if(f>0){var m=this.get(f-1);if(m.equals2D(d))return null}if(v>f){var y=this.get(f);if(y.equals2D(d))return null}}}I.prototype.add.call(this,f,d)}}else if(4===arguments.length){var x=arguments[0],E=arguments[1],N=arguments[2],C=arguments[3],S=1;N>C&&(S=-1);for(var c=N;c!==C;c+=S)this.add(x[c],E);return!0}},closeRing:function(){this.size()>0&&this.add(new g(this.get(0)),!1)},interfaces_:function(){return[]},getClass:function(){return N}}),N.coordArrayType=new Array(0).fill(null),e(C.prototype,{getArea:function(){return this.getWidth()*this.getHeight()},equals:function(t){if(!(t instanceof C))return!1;var e=t;return this.isNull()?e.isNull():this.maxx===e.getMaxX()&&this.maxy===e.getMaxY()&&this.minx===e.getMinX()&&this.miny===e.getMinY()},intersection:function(t){if(this.isNull()||t.isNull()||!this.intersects(t))return new C;var e=this.minx>t.minx?this.minx:t.minx,n=this.miny>t.miny?this.miny:t.miny,i=this.maxx=this.minx&&e.getMaxX()<=this.maxx&&e.getMinY()>=this.miny&&e.getMaxY()<=this.maxy}}else if(2===arguments.length){var n=arguments[0],i=arguments[1];return this.isNull()?!1:n>=this.minx&&n<=this.maxx&&i>=this.miny&&i<=this.maxy}},intersects:function(){if(1===arguments.length){if(arguments[0]instanceof C){var t=arguments[0];return this.isNull()||t.isNull()?!1:!(t.minx>this.maxx||t.maxxthis.maxy||t.maxythis.maxx||nthis.maxy||ithis.maxx&&(this.maxx=e.maxx),e.minythis.maxy&&(this.maxy=e.maxy))}}else if(2===arguments.length){var n=arguments[0],i=arguments[1];this.isNull()?(this.minx=n,this.maxx=n,this.miny=i,this.maxy=i):(nthis.maxx&&(this.maxx=n),ithis.maxy&&(this.maxy=i))}},minExtent:function(){if(this.isNull())return 0;var t=this.getWidth(),e=this.getHeight();return e>t?t:e},getWidth:function(){return this.isNull()?0:this.maxx-this.minx},compareTo:function(t){var e=t;return this.isNull()?e.isNull()?0:-1:e.isNull()?1:this.minxe.minx?1:this.minye.miny?1:this.maxxe.maxx?1:this.maxye.maxy?1:0},translate:function(t,e){return this.isNull()?null:void this.init(this.getMinX()+t,this.getMaxX()+t,this.getMinY()+e,this.getMaxY()+e)},toString:function(){return"Env["+this.minx+" : "+this.maxx+", "+this.miny+" : "+this.maxy+"]"},setToNull:function(){this.minx=0,this.maxx=-1,this.miny=0,this.maxy=-1},getHeight:function(){return this.isNull()?0:this.maxy-this.miny},maxExtent:function(){if(this.isNull())return 0;var t=this.getWidth(),e=this.getHeight();return t>e?t:e},expandBy:function(){if(1===arguments.length){var t=arguments[0];this.expandBy(t,t)}else if(2===arguments.length){var e=arguments[0],n=arguments[1];if(this.isNull())return null;this.minx-=e,this.maxx+=e,this.miny-=n,this.maxy+=n,(this.minx>this.maxx||this.miny>this.maxy)&&this.setToNull()}},contains:function(){if(1===arguments.length){if(arguments[0]instanceof C){var t=arguments[0];return this.covers(t)}if(arguments[0]instanceof g){var e=arguments[0];return this.covers(e)}}else if(2===arguments.length){var n=arguments[0],i=arguments[1];return this.covers(n,i)}},centre:function(){return this.isNull()?null:new g((this.getMinX()+this.getMaxX())/2,(this.getMinY()+this.getMaxY())/2)},init:function(){if(0===arguments.length)this.setToNull();else if(1===arguments.length){if(arguments[0]instanceof g){var t=arguments[0];this.init(t.x,t.x,t.y,t.y)}else if(arguments[0]instanceof C){var e=arguments[0];this.minx=e.minx,this.maxx=e.maxx,this.miny=e.miny,this.maxy=e.maxy}}else if(2===arguments.length){var n=arguments[0],i=arguments[1];this.init(n.x,i.x,n.y,i.y)}else if(4===arguments.length){var r=arguments[0],s=arguments[1],o=arguments[2],a=arguments[3];s>r?(this.minx=r,this.maxx=s):(this.minx=s,this.maxx=r),a>o?(this.miny=o,this.maxy=a):(this.miny=a,this.maxy=o)}},getMaxY:function(){return this.maxy},distance:function(t){if(this.intersects(t))return 0;var e=0;this.maxxt.maxx&&(e=this.minx-t.maxx);var n=0;return this.maxyt.maxy&&(n=this.miny-t.maxy),0===e?n:0===n?e:Math.sqrt(e*e+n*n)},hashCode:function(){var t=17;return t=37*t+g.hashCode(this.minx),t=37*t+g.hashCode(this.maxx),t=37*t+g.hashCode(this.miny),t=37*t+g.hashCode(this.maxy)},interfaces_:function(){return[s,u]},getClass:function(){return C}}),C.intersects=function(){if(3===arguments.length){var t=arguments[0],e=arguments[1],n=arguments[2];return n.x>=(t.xe.x?t.x:e.x)&&n.y>=(t.ye.y?t.y:e.y)}if(4===arguments.length){var i=arguments[0],r=arguments[1],s=arguments[2],o=arguments[3],a=Math.min(s.x,o.x),u=Math.max(s.x,o.x),l=Math.min(i.x,r.x),h=Math.max(i.x,r.x);return l>u?!1:a>h?!1:(a=Math.min(s.y,o.y),u=Math.max(s.y,o.y),l=Math.min(i.y,r.y),h=Math.max(i.y,r.y),l>u?!1:!(a>h))}},C.serialVersionUID=0x51845cd552189800,h(w,S),e(w.prototype,{interfaces_:function(){return[]},getClass:function(){return w}}),e(L.prototype,{interfaces_:function(){return[]},getClass:function(){return L}}),L.toLocationSymbol=function(t){switch(t){case L.EXTERIOR:return"e";case L.BOUNDARY:return"b";case L.INTERIOR:return"i";case L.NONE:return"-"}throw new i("Unknown location value: "+t)},L.INTERIOR=0,L.BOUNDARY=1,L.EXTERIOR=2,L.NONE=-1,e(T.prototype,{interfaces_:function(){return[]},getClass:function(){return T}}),T.log10=function(t){var e=Math.log(t);return r.isInfinite(e)?e:r.isNaN(e)?e:e/T.LOG_10},T.min=function(t,e,n,i){var r=t;return r>e&&(r=e),r>n&&(r=n),r>i&&(r=i),r},T.clamp=function(){if("number"==typeof arguments[2]&&"number"==typeof arguments[0]&&"number"==typeof arguments[1]){var t=arguments[0],e=arguments[1],n=arguments[2];return e>t?e:t>n?n:t}if(Number.isInteger(arguments[2])&&Number.isInteger(arguments[0])&&Number.isInteger(arguments[1])){var i=arguments[0],r=arguments[1],s=arguments[2];return r>i?r:i>s?s:i}},T.wrap=function(t,e){return 0>t?e- -t%e:t%e},T.max=function(){ +if(3===arguments.length){var t=arguments[0],e=arguments[1],n=arguments[2],i=t;return e>i&&(i=e),n>i&&(i=n),i}if(4===arguments.length){var r=arguments[0],s=arguments[1],o=arguments[2],a=arguments[3],i=r;return s>i&&(i=s),o>i&&(i=o),a>i&&(i=a),i}},T.average=function(t,e){return(t+e)/2},T.LOG_10=Math.log(10),P.prototype.append=function(t){this.str+=t},P.prototype.setCharAt=function(t,e){return this.str.substr(0,t)+e+this.str.substr(t+1)},P.prototype.toString=function(t){return this.str},b.prototype.intValue=function(){return this.value},b.prototype.compareTo=function(t){return this.valuet?1:0},b.isNaN=function(t){return Number.isNaN(t)},O.isWhitespace=function(t){return 32>=t&&t>=0||127==t},O.toUpperCase=function(t){return t.toUpperCase()},e(_.prototype,{le:function(t){return this.hi=u;u++){t&&u===s&&o.append(".");var l=Math.trunc(n.hi);if(0>l)break;var h=!1,c=0;l>9?(h=!0,c="9"):c="0"+l,o.append(c),n=n.subtract(_.valueOf(l)).multiply(_.TEN),h&&n.selfAdd(_.TEN);var f=!0,g=_.magnitude(n.hi);if(0>g&&Math.abs(g)>=a-u&&(f=!1),!f)break}return e[0]=i,o.toString()},sqr:function(){return this.multiply(this)},doubleValue:function(){return this.hi+this.lo},subtract:function(){if(arguments[0]instanceof _){var t=arguments[0];return this.add(t.negate())}if("number"==typeof arguments[0]){var e=arguments[0];return this.add(-e)}},equals:function(){if(1===arguments.length){var t=arguments[0];return this.hi===t.hi&&this.lo===t.lo}},isZero:function(){return 0===this.hi&&0===this.lo},selfSubtract:function(){if(arguments[0]instanceof _){var t=arguments[0];return this.isNaN()?this:this.selfAdd(-t.hi,-t.lo)}if("number"==typeof arguments[0]){var e=arguments[0];return this.isNaN()?this:this.selfAdd(-e,0)}},getSpecialNumberString:function(){return this.isZero()?"0.0":this.isNaN()?"NaN ":null},min:function(t){return this.le(t)?this:t},selfDivide:function(){if(1===arguments.length){if(arguments[0]instanceof _){var t=arguments[0];return this.selfDivide(t.hi,t.lo)}if("number"==typeof arguments[0]){var e=arguments[0];return this.selfDivide(e,0)}}else if(2===arguments.length){var n=arguments[0],i=arguments[1],r=null,s=null,o=null,a=null,u=null,l=null,h=null,c=null;return u=this.hi/n,l=_.SPLIT*u,r=l-u,c=_.SPLIT*n,r=l-r,s=u-r,o=c-n,h=u*n,o=c-o,a=n-o,c=r*o-h+r*a+s*o+s*a,l=(this.hi-h-c+this.lo-u*i)/n,c=u+l,this.hi=c,this.lo=u-c+l,this}},dump:function(){return"DD<"+this.hi+", "+this.lo+">"},divide:function(){if(arguments[0]instanceof _){var t=arguments[0],e=null,n=null,i=null,s=null,o=null,a=null,u=null,l=null;o=this.hi/t.hi,a=_.SPLIT*o,e=a-o,l=_.SPLIT*t.hi,e=a-e,n=o-e,i=l-t.hi,u=o*t.hi,i=l-i,s=t.hi-i,l=e*i-u+e*s+n*i+n*s,a=(this.hi-u-l+this.lo-o*t.lo)/t.hi,l=o+a;var h=l,c=o-l+a;return new _(h,c)}if("number"==typeof arguments[0]){var f=arguments[0];return r.isNaN(f)?_.createNaN():_.copy(this).selfDivide(f,0)}},ge:function(t){return this.hi>t.hi||this.hi===t.hi&&this.lo>=t.lo},pow:function(t){if(0===t)return _.valueOf(1);var e=new _(this),n=_.valueOf(1),i=Math.abs(t);if(i>1)for(;i>0;)i%2===1&&n.selfMultiply(e),i/=2,i>0&&(e=e.sqr());else n=e;return 0>t?n.reciprocal():n},ceil:function(){if(this.isNaN())return _.NaN;var t=Math.ceil(this.hi),e=0;return t===this.hi&&(e=Math.ceil(this.lo)),new _(t,e)},compareTo:function(t){var e=t;return this.hie.hi?1:this.loe.lo?1:0},rint:function(){if(this.isNaN())return this;var t=this.add(.5);return t.floor()},setValue:function(){if(arguments[0]instanceof _){var t=arguments[0];return this.init(t),this}if("number"==typeof arguments[0]){var e=arguments[0];return this.init(e),this}},max:function(t){return this.ge(t)?this:t},sqrt:function(){if(this.isZero())return _.valueOf(0);if(this.isNegative())return _.NaN;var t=1/Math.sqrt(this.hi),e=this.hi*t,n=_.valueOf(e),i=this.subtract(n.sqr()),r=i.hi*(.5*t);return n.add(r)},selfAdd:function(){if(1===arguments.length){if(arguments[0]instanceof _){var t=arguments[0];return this.selfAdd(t.hi,t.lo)}if("number"==typeof arguments[0]){var e=arguments[0],n=null,i=null,r=null,s=null,o=null,a=null;return r=this.hi+e,o=r-this.hi,s=r-o,s=e-o+(this.hi-s),a=s+this.lo,n=r+a,i=a+(r-n),this.hi=n+i,this.lo=i+(n-this.hi),this}}else if(2===arguments.length){var u=arguments[0],l=arguments[1],n=null,i=null,h=null,c=null,r=null,s=null,o=null,a=null;r=this.hi+u,h=this.lo+l,o=r-this.hi,a=h-this.lo,s=r-o,c=h-a,s=u-o+(this.hi-s),c=l-a+(this.lo-c),o=s+h,n=r+o,i=o+(r-n),o=c+i;var f=n+o,g=o+(n-f);return this.hi=f,this.lo=g,this}},selfMultiply:function(){if(1===arguments.length){if(arguments[0]instanceof _){var t=arguments[0];return this.selfMultiply(t.hi,t.lo)}if("number"==typeof arguments[0]){var e=arguments[0];return this.selfMultiply(e,0)}}else if(2===arguments.length){var n=arguments[0],i=arguments[1],r=null,s=null,o=null,a=null,u=null,l=null;u=_.SPLIT*this.hi,r=u-this.hi,l=_.SPLIT*n,r=u-r,s=this.hi-r,o=l-n,u=this.hi*n,o=l-o,a=n-o,l=r*o-u+r*a+s*o+s*a+(this.hi*i+this.lo*n);var h=u+l;r=u-h;var c=l+r;return this.hi=h,this.lo=c,this}},selfSqr:function(){return this.selfMultiply(this)},floor:function(){if(this.isNaN())return _.NaN;var t=Math.floor(this.hi),e=0;return t===this.hi&&(e=Math.floor(this.lo)),new _(t,e)},negate:function(){return this.isNaN()?this:new _(-this.hi,-this.lo)},clone:function(){try{return null}catch(t){if(t instanceof CloneNotSupportedException)return null;throw t}finally{}},multiply:function(){if(arguments[0]instanceof _){var t=arguments[0];return t.isNaN()?_.createNaN():_.copy(this).selfMultiply(t)}if("number"==typeof arguments[0]){var e=arguments[0];return r.isNaN(e)?_.createNaN():_.copy(this).selfMultiply(e,0)}},isNaN:function(){return r.isNaN(this.hi)},intValue:function(){return Math.trunc(this.hi)},toString:function(){var t=_.magnitude(this.hi);return t>=-3&&20>=t?this.toStandardNotation():this.toSciNotation()},toStandardNotation:function(){var t=this.getSpecialNumberString();if(null!==t)return t;var e=new Array(1).fill(null),n=this.extractSignificantDigits(!0,e),i=e[0]+1,r=n;if("."===n.charAt(0))r="0"+n;else if(0>i)r="0."+_.stringOfChar("0",-i)+n;else if(-1===n.indexOf(".")){var s=i-n.length,o=_.stringOfChar("0",s);r=n+o+".0"}return this.isNegative()?"-"+r:r},reciprocal:function(){var t=null,e=null,n=null,i=null,r=null,s=null,o=null,a=null;r=1/this.hi,s=_.SPLIT*r,t=s-r,a=_.SPLIT*this.hi,t=s-t,e=r-t,n=a-this.hi,o=r*this.hi,n=a-n,i=this.hi-n,a=t*n-o+t*i+e*n+e*i,s=(1-o-a-r*this.lo)/this.hi;var u=r+s,l=r-u+s;return new _(u,l)},toSciNotation:function(){if(this.isZero())return _.SCI_NOT_ZERO;var t=this.getSpecialNumberString();if(null!==t)return t;var e=new Array(1).fill(null),n=this.extractSignificantDigits(!1,e),i=_.SCI_NOT_EXPONENT_CHAR+e[0];if("0"===n.charAt(0))throw new IllegalStateException("Found leading zero: "+n);var r="";n.length>1&&(r=n.substring(1));var s=n.charAt(0)+"."+r;return this.isNegative()?"-"+s+i:s+i},abs:function(){return this.isNaN()?_.NaN:this.isNegative()?this.negate():new _(this)},isPositive:function(){return this.hi>0||0===this.hi&&this.lo>0},lt:function(t){return this.hit.hi||this.hi===t.hi&&this.lo>t.lo},isNegative:function(){return this.hi<0||0===this.hi&&this.lo<0},trunc:function(){return this.isNaN()?_.NaN:this.isPositive()?this.floor():this.ceil()},signum:function(){return this.hi>0?1:this.hi<0?-1:this.lo>0?1:this.lo<0?-1:0},interfaces_:function(){return[u,s,o]},getClass:function(){return _}}),_.sqr=function(t){return _.valueOf(t).selfMultiply(t)},_.valueOf=function(){if("string"==typeof arguments[0]){var t=arguments[0];return _.parse(t)}if("number"==typeof arguments[0]){var e=arguments[0];return new _(e)}},_.sqrt=function(t){return _.valueOf(t).sqrt()},_.parse=function(t){for(var e=0,n=t.length;O.isWhitespace(t.charAt(e));)e++;var i=!1;if(n>e){var r=t.charAt(e);"-"!==r&&"+"!==r||(e++,"-"===r&&(i=!0))}for(var s=new _,o=0,a=0,u=0;;){if(e>=n)break;var l=t.charAt(e);if(e++,O.isDigit(l)){var h=l-"0";s.selfMultiply(_.TEN),s.selfAdd(h),o++}else{if("."!==l){if("e"===l||"E"===l){var c=t.substring(e);try{u=b.parseInt(c)}catch(f){throw f instanceof NumberFormatException?new NumberFormatException("Invalid exponent "+c+" in string "+t):f}finally{}break}throw new NumberFormatException("Unexpected character '"+l+"' at position "+e+" in string "+t)}a=o}}var g=s,d=o-a-u;if(0===d)g=s;else if(d>0){var p=_.TEN.pow(d);g=s.divide(p)}else if(0>d){var p=_.TEN.pow(-d);g=s.multiply(p)}return i?g.negate():g},_.createNaN=function(){return new _(r.NaN,r.NaN)},_.copy=function(t){return new _(t)},_.magnitude=function(t){var e=Math.abs(t),n=Math.log(e)/Math.log(10),i=Math.trunc(Math.floor(n)),r=Math.pow(10,i);return e>=10*r&&(i+=1),i},_.stringOfChar=function(t,e){for(var n=new P,i=0;e>i;i++)n.append(t);return n.toString()},_.PI=new _(3.141592653589793,1.2246467991473532e-16),_.TWO_PI=new _(6.283185307179586,2.4492935982947064e-16),_.PI_2=new _(1.5707963267948966,6.123233995736766e-17),_.E=new _(2.718281828459045,1.4456468917292502e-16),_.NaN=new _(r.NaN,r.NaN),_.EPS=1.23259516440783e-32,_.SPLIT=134217729,_.MAX_PRINT_DIGITS=32,_.TEN=_.valueOf(10),_.ONE=_.valueOf(1),_.SCI_NOT_EXPONENT_CHAR="E",_.SCI_NOT_ZERO="0.0E0",e(M.prototype,{interfaces_:function(){return[]},getClass:function(){return M}}),M.orientationIndex=function(t,e,n){var i=M.orientationIndexFilter(t,e,n);if(1>=i)return i;var r=_.valueOf(e.x).selfAdd(-t.x),s=_.valueOf(e.y).selfAdd(-t.y),o=_.valueOf(n.x).selfAdd(-e.x),a=_.valueOf(n.y).selfAdd(-e.y);return r.selfMultiply(a).selfSubtract(s.selfMultiply(o)).signum()},M.signOfDet2x2=function(t,e,n,i){var r=t.multiply(i).selfSubtract(e.multiply(n));return r.signum()},M.intersection=function(t,e,n,i){var r=_.valueOf(i.y).selfSubtract(n.y).selfMultiply(_.valueOf(e.x).selfSubtract(t.x)),s=_.valueOf(i.x).selfSubtract(n.x).selfMultiply(_.valueOf(e.y).selfSubtract(t.y)),o=r.subtract(s),a=_.valueOf(i.x).selfSubtract(n.x).selfMultiply(_.valueOf(t.y).selfSubtract(n.y)),u=_.valueOf(i.y).selfSubtract(n.y).selfMultiply(_.valueOf(t.x).selfSubtract(n.x)),l=a.subtract(u),h=l.selfDivide(o).doubleValue(),c=_.valueOf(t.x).selfAdd(_.valueOf(e.x).selfSubtract(t.x).selfMultiply(h)).doubleValue(),f=_.valueOf(e.x).selfSubtract(t.x).selfMultiply(_.valueOf(t.y).selfSubtract(n.y)),d=_.valueOf(e.y).selfSubtract(t.y).selfMultiply(_.valueOf(t.x).selfSubtract(n.x)),p=f.subtract(d),v=p.selfDivide(o).doubleValue(),m=_.valueOf(n.y).selfAdd(_.valueOf(i.y).selfSubtract(n.y).selfMultiply(v)).doubleValue();return new g(c,m)},M.orientationIndexFilter=function(t,e,n){var i=null,r=(t.x-n.x)*(e.y-n.y),s=(t.y-n.y)*(e.x-n.x),o=r-s;if(r>0){if(0>=s)return M.signum(o);i=r+s}else{if(!(0>r))return M.signum(o);if(s>=0)return M.signum(o);i=-r-s}var a=M.DP_SAFE_EPSILON*i;return o>=a||-o>=a?M.signum(o):2},M.signum=function(t){return t>0?1:0>t?-1:0},M.DP_SAFE_EPSILON=1e-15,e(D.prototype,{setOrdinate:function(t,e,n){},size:function(){},getOrdinate:function(t,e){},getCoordinate:function(){if(1===arguments.length){arguments[0]}else if(2===arguments.length){arguments[0],arguments[1]}},getCoordinateCopy:function(t){},getDimension:function(){},getX:function(t){},clone:function(){},expandEnvelope:function(t){},copy:function(){},getY:function(t){},toCoordinateArray:function(){},interfaces_:function(){return[o]},getClass:function(){return D}}),D.X=0,D.Y=1,D.Z=2,D.M=3,A.arraycopy=function(t,e,n,i,r){for(var s=0,o=e;e+r>o;o++)n[i+s]=t[o],s++},A.getProperty=function(t){return{"line.separator":"\n"}[t]},e(F.prototype,{getY:function(){var t=this.y/this.w;if(r.isNaN(t)||r.isInfinite(t))throw new w;return t},getX:function(){var t=this.x/this.w;if(r.isNaN(t)||r.isInfinite(t))throw new w;return t},getCoordinate:function(){var t=new g;return t.x=this.getX(),t.y=this.getY(),t},interfaces_:function(){return[]},getClass:function(){return F}}),F.intersection=function(t,e,n,i){var s=t.y-e.y,o=e.x-t.x,a=t.x*e.y-e.x*t.y,u=n.y-i.y,l=i.x-n.x,h=n.x*i.y-i.x*n.y,c=o*h-l*a,f=u*a-s*h,d=s*l-u*o,p=c/d,v=f/d;if(r.isNaN(p)||r.isInfinite(p)||r.isNaN(v)||r.isInfinite(v))throw new w;return new g(p,v)},e(G.prototype,{create:function(){if(1===arguments.length){if(arguments[0]instanceof Array){arguments[0]}else if(R(arguments[0],D)){arguments[0]}}else if(2===arguments.length){arguments[0],arguments[1]}},interfaces_:function(){return[]},getClass:function(){return G}}),e(q.prototype,{filter:function(t){},interfaces_:function(){return[]},getClass:function(){return q}}),e(B.prototype,{isGeometryCollection:function(){return this.getSortIndex()===B.SORTINDEX_GEOMETRYCOLLECTION},getFactory:function(){return this.factory},getGeometryN:function(t){return this},getArea:function(){return 0},isRectangle:function(){return!1},equals:function(){if(1===arguments.length){if(arguments[0]instanceof B){var t=arguments[0];return null===t?!1:this.equalsTopo(t)}if(arguments[0]instanceof Object){var e=arguments[0];if(!(e instanceof B))return!1;var n=e;return this.equalsExact(n)}}},equalsExact:function(t){return this===t||this.equalsExact(t,0)},geometryChanged:function(){this.apply(B.geometryChangedFilter)},geometryChangedAction:function(){this.envelope=null},equalsNorm:function(t){return null===t?!1:this.norm().equalsExact(t.norm())},getLength:function(){return 0},getNumGeometries:function(){return 1},compareTo:function(){if(1===arguments.length){var t=arguments[0],e=t;return this.getSortIndex()!==e.getSortIndex()?this.getSortIndex()-e.getSortIndex():this.isEmpty()&&e.isEmpty()?0:this.isEmpty()?-1:e.isEmpty()?1:this.compareToSameClass(t)}if(2===arguments.length){var n=arguments[0],i=arguments[1],e=n;return this.getSortIndex()!==e.getSortIndex()?this.getSortIndex()-e.getSortIndex():this.isEmpty()&&e.isEmpty()?0:this.isEmpty()?-1:e.isEmpty()?1:this.compareToSameClass(n,i)}},getUserData:function(){return this.userData},getSRID:function(){return this.SRID},getEnvelope:function(){return this.getFactory().toGeometry(this.getEnvelopeInternal())},checkNotGeometryCollection:function(t){if(t.getSortIndex()===B.SORTINDEX_GEOMETRYCOLLECTION)throw new i("This method does not support GeometryCollection arguments")},equal:function(t,e,n){return 0===n?t.equals(e):t.distance(e)<=n},norm:function(){var t=this.copy();return t.normalize(),t},getPrecisionModel:function(){return this.factory.getPrecisionModel()},getEnvelopeInternal:function(){return null===this.envelope&&(this.envelope=this.computeEnvelopeInternal()),new C(this.envelope)},setSRID:function(t){this.SRID=t},setUserData:function(t){this.userData=t},compare:function(t,e){for(var n=t.iterator(),i=e.iterator();n.hasNext()&&i.hasNext();){var r=n.next(),s=i.next(),o=r.compareTo(s);if(0!==o)return o}return n.hasNext()?1:i.hasNext()?-1:0},hashCode:function(){return this.getEnvelopeInternal().hashCode()},isGeometryCollectionOrDerived:function(){return this.getSortIndex()===B.SORTINDEX_GEOMETRYCOLLECTION||this.getSortIndex()===B.SORTINDEX_MULTIPOINT||this.getSortIndex()===B.SORTINDEX_MULTILINESTRING||this.getSortIndex()===B.SORTINDEX_MULTIPOLYGON},interfaces_:function(){return[o,s,u]},getClass:function(){return B}}),B.hasNonEmptyElements=function(t){for(var e=0;e0},interfaces_:function(){return[V]},getClass:function(){return Y}}),e(U.prototype,{isInBoundary:function(t){return t>1},interfaces_:function(){return[V]},getClass:function(){return U}}),e(X.prototype,{isInBoundary:function(t){return 1===t},interfaces_:function(){return[V]},getClass:function(){return X}}),V.Mod2BoundaryNodeRule=k,V.EndPointBoundaryNodeRule=Y,V.MultiValentEndPointBoundaryNodeRule=U,V.MonoValentEndPointBoundaryNodeRule=X,V.MOD2_BOUNDARY_RULE=new k,V.ENDPOINT_BOUNDARY_RULE=new Y,V.MULTIVALENT_ENDPOINT_BOUNDARY_RULE=new U,V.MONOVALENT_ENDPOINT_BOUNDARY_RULE=new X,V.OGC_SFS_BOUNDARY_RULE=V.MOD2_BOUNDARY_RULE,e(H.prototype,{interfaces_:function(){return[]},getClass:function(){return H}}),H.isRing=function(t){return t.length<4?!1:!!t[0].equals2D(t[t.length-1])},H.ptNotInList=function(t,e){for(var n=0;nn)return null;var i=new Array(t.length).fill(null);A.arraycopy(t,n,i,0,t.length-n),A.arraycopy(t,0,i,t.length-n,n),A.arraycopy(i,0,t,0,t.length)},H.equals=function(){if(2===arguments.length){var t=arguments[0],e=arguments[1];if(t===e)return!0;if(null===t||null===e)return!1;if(t.length!==e.length)return!1;for(var n=0;n=i;i++){var r=t[i];t[i]=t[e-i],t[e-i]=r}},H.removeNull=function(t){for(var e=0,n=0;nn;n++)s[o+n]=new g(i[r+n])},H.isEqualReversed=function(t,e){for(var n=0;n=t?e:[]},H.indexOf=function(t,e){for(var n=0;n0)&&(e=t[n]);return e},H.extract=function(t,e,n){e=T.clamp(e,0,t.length),n=T.clamp(n,-1,t.length);var i=n-e+1;0>n&&(i=0),e>=t.length&&(i=0),e>n&&(i=0);var r=new Array(i).fill(null);if(0===i)return r;for(var s=0,o=e;n>=o;o++)r[s++]=t[o];return r},e(W.prototype,{compare:function(t,e){var n=t,i=e;return H.compare(n,i)},interfaces_:function(){return[a]},getClass:function(){return W}}),e(j.prototype,{compare:function(t,e){var n=t,i=e;if(n.lengthi.length)return 1;if(0===n.length)return 0;var r=H.compare(n,i),s=H.isEqualReversed(n,i);return s?0:r},OLDcompare:function(t,e){var n=t,i=e;if(n.lengthi.length)return 1;if(0===n.length)return 0;for(var r=H.increasingDirection(n),s=H.increasingDirection(i),o=r>0?0:n.length-1,a=s>0?0:n.length-1,u=0;ue;e++){var i=this.array_[e];if(i===t)return!0}return!1},J.prototype.add=function(t){return this.contains(t)?!1:(this.array_.push(t),!0)},J.prototype.addAll=function(t){for(var e=t.iterator();e.hasNext();)this.add(e.next());return!0},J.prototype.remove=function(t){throw new javascript.util.OperationNotSupported},J.prototype.size=function(){return this.array_.length},J.prototype.isEmpty=function(){return 0===this.array_.length},J.prototype.toArray=function(){for(var t=[],e=0,n=this.array_.length;n>e;e++)t.push(this.array_[e]);return t},J.prototype.iterator=function(){return new Js(this)};var Js=function(t){this.hashSet_=t,this.position_=0};Js.prototype.next=function(){if(this.position_===this.hashSet_.size())throw new x;return this.hashSet_.array_[this.position_++]},Js.prototype.hasNext=function(){return this.position_n)e=e.left;else{if(!(n>0))return e.value;e=e.right}}return null},rt.prototype.put=function(t,e){if(null===this.root_)return this.root_={key:t,value:e,left:null,right:null,parent:null,color:$s,getValue:function(){return this.value},getKey:function(){return this.key}},this.size_=1,null;var n,i,r=this.root_;do if(n=r,i=t.compareTo(r.key),0>i)r=r.left;else{if(!(i>0)){var s=r.value;return r.value=e,s}r=r.right}while(null!==r);var o={key:t,left:null,right:null,value:e,parent:n,color:$s,getValue:function(){return this.value},getKey:function(){return this.key}};return 0>i?n.left=o:n.right=o,this.fixAfterInsertion(o),this.size_++,null},rt.prototype.fixAfterInsertion=function(t){for(t.color=to;null!=t&&t!=this.root_&&t.parent.color==to;)if(tt(t)==nt(tt(tt(t)))){var e=it(tt(tt(t)));$(e)==to?(et(tt(t),$s),et(e,$s),et(tt(tt(t)),to),t=tt(tt(t))):(t==it(tt(t))&&(t=tt(t),this.rotateLeft(t)),et(tt(t),$s),et(tt(tt(t)),to),this.rotateRight(tt(tt(t))))}else{var e=nt(tt(tt(t)));$(e)==to?(et(tt(t),$s),et(e,$s),et(tt(tt(t)),to),t=tt(tt(t))):(t==nt(tt(t))&&(t=tt(t),this.rotateRight(t)),et(tt(t),$s),et(tt(tt(t)),to),this.rotateLeft(tt(tt(t))))}this.root_.color=$s},rt.prototype.values=function(){var t=new I,e=this.getFirstEntry();if(null!==e)for(t.add(e.value);null!==(e=rt.successor(e));)t.add(e.value);return t},rt.prototype.entrySet=function(){var t=new J,e=this.getFirstEntry();if(null!==e)for(t.add(e);null!==(e=rt.successor(e));)t.add(e);return t},rt.prototype.rotateLeft=function(t){if(null!=t){var e=t.right;t.right=e.left,null!=e.left&&(e.left.parent=t),e.parent=t.parent,null==t.parent?this.root_=e:t.parent.left==t?t.parent.left=e:t.parent.right=e,e.left=t,t.parent=e}},rt.prototype.rotateRight=function(t){if(null!=t){var e=t.left;t.left=e.right,null!=e.right&&(e.right.parent=t),e.parent=t.parent,null==t.parent?this.root_=e:t.parent.right==t?t.parent.right=e:t.parent.left=e,e.right=t,t.parent=e}},rt.prototype.getFirstEntry=function(){var t=this.root_;if(null!=t)for(;null!=t.left;)t=t.left;return t},rt.successor=function(t){if(null===t)return null;if(null!==t.right){for(var e=t.right;null!==e.left;)e=e.left;return e}for(var e=t.parent,n=t;null!==e&&n===e.right;)n=e,e=e.parent;return e},rt.prototype.size=function(){return this.size_},e(st.prototype,{interfaces_:function(){return[]},getClass:function(){return st}}),ot.prototype=new Q,at.prototype=new ot,at.prototype.contains=function(t){for(var e=0,n=this.array_.length;n>e;e++){var i=this.array_[e];if(0===i.compareTo(t))return!0}return!1},at.prototype.add=function(t){if(this.contains(t))return!1;for(var e=0,n=this.array_.length;n>e;e++){var i=this.array_[e];if(1===i.compareTo(t))return this.array_.splice(e,0,t),!0}return this.array_.push(t),!0},at.prototype.addAll=function(t){for(var e=t.iterator();e.hasNext();)this.add(e.next());return!0},at.prototype.remove=function(t){throw new E},at.prototype.size=function(){return this.array_.length},at.prototype.isEmpty=function(){return 0===this.array_.length},at.prototype.toArray=function(){for(var t=[],e=0,n=this.array_.length;n>e;e++)t.push(this.array_[e]);return t},at.prototype.iterator=function(){return new eo(this)};var eo=function(t){this.treeSet_=t,this.position_=0};eo.prototype.next=function(){if(this.position_===this.treeSet_.size())throw new x;return this.treeSet_.array_[this.position_++]},eo.prototype.hasNext=function(){return this.position_n;n++)e.add(t[n]);return e},e(lt.prototype,{interfaces_:function(){return[]},getClass:function(){return lt}}),lt.toDimensionSymbol=function(t){switch(t){case lt.FALSE:return lt.SYM_FALSE;case lt.TRUE:return lt.SYM_TRUE;case lt.DONTCARE:return lt.SYM_DONTCARE;case lt.P:return lt.SYM_P;case lt.L:return lt.SYM_L;case lt.A:return lt.SYM_A}throw new i("Unknown dimension value: "+t)},lt.toDimensionValue=function(t){switch(O.toUpperCase(t)){case lt.SYM_FALSE:return lt.FALSE;case lt.SYM_TRUE:return lt.TRUE;case lt.SYM_DONTCARE:return lt.DONTCARE;case lt.SYM_P:return lt.P;case lt.SYM_L:return lt.L;case lt.SYM_A:return lt.A}throw new i("Unknown dimension symbol: "+t)},lt.P=0,lt.L=1,lt.A=2,lt.FALSE=-1,lt.TRUE=-2,lt.DONTCARE=-3,lt.SYM_FALSE="F",lt.SYM_TRUE="T",lt.SYM_DONTCARE="*",lt.SYM_P="0",lt.SYM_L="1",lt.SYM_A="2",e(ht.prototype,{filter:function(t){},interfaces_:function(){return[]},getClass:function(){return ht}}),e(ct.prototype,{filter:function(t,e){},isDone:function(){},isGeometryChanged:function(){},interfaces_:function(){return[]},getClass:function(){return ct}}),h(ft,B),e(ft.prototype,{computeEnvelopeInternal:function(){for(var t=new C,e=0;eu&&a>u;){var l=this.getGeometryN(u),h=s.getGeometryN(u),c=l.compareToSameClass(h,r);if(0!==c)return c;u++}return o>u?1:a>u?-1:0}},apply:function(){if(R(arguments[0],z))for(var t=arguments[0],e=0;ei;i++)n[i]=t;return new String(n)},Nt.getStackTrace=function(){if(1===arguments.length){var t=arguments[0],e=new xt,n=new vt(e);return t.printStackTrace(n),e.toString()}if(2===arguments.length){for(var i=arguments[0],r=arguments[1],s="",o=new mt(Nt.getStackTrace(i)),a=new It(o),u=0;r>u;u++)try{s+=a.readLine()+Nt.NEWLINE}catch(l){if(!(l instanceof Et))throw l;f.shouldNeverReachHere()}finally{}return s}},Nt.split=function(t,e){for(var n=e.length,i=new I,r=""+t,s=r.indexOf(e);s>=0;){var o=r.substring(0,s);i.add(o),r=r.substring(s+n),s=r.indexOf(e)}r.length>0&&i.add(r);for(var a=new Array(i.size()).fill(null),u=0;us;s++)n.setOrdinate(i,s,t.getOrdinate(e,s))},Ct.isRing=function(t){var e=t.size();return 0===e?!0:3>=e?!1:t.getOrdinate(0,D.X)===t.getOrdinate(e-1,D.X)&&t.getOrdinate(0,D.Y)===t.getOrdinate(e-1,D.Y)},Ct.isEqual=function(t,e){var n=t.size(),i=e.size();if(n!==i)return!1;for(var s=Math.min(t.getDimension(),e.getDimension()),o=0;n>o;o++)for(var a=0;s>a;a++){var u=t.getOrdinate(o,a),l=e.getOrdinate(o,a);if(!(t.getOrdinate(o,a)===e.getOrdinate(o,a)||r.isNaN(u)&&r.isNaN(l)))return!1}return!0},Ct.extend=function(t,e,n){var i=t.create(n,e.getDimension()),r=e.size();if(Ct.copy(e,0,i,0,r),r>0)for(var s=r;n>s;s++)Ct.copy(e,r-1,i,s,1);return i},Ct.reverse=function(t){for(var e=t.size()-1,n=Math.trunc(e/2),i=0;n>=i;i++)Ct.swap(t,i,e-i)},Ct.swap=function(t,e,n){if(e===n)return null;for(var i=0;is;s++)Ct.copyCoord(t,e+s,n,i+s)},Ct.toString=function(){if(1===arguments.length){var t=arguments[0],e=t.size();if(0===e)return"()";var n=t.getDimension(),i=new P;i.append("(");for(var r=0;e>r;r++){r>0&&i.append(" ");for(var s=0;n>s;s++)s>0&&i.append(","),i.append(Nt.toString(t.getOrdinate(r,s)))}return i.append(")"),i.toString()}},Ct.ensureValidRing=function(t,e){var n=e.size();if(0===n)return e;if(3>=n)return Ct.createClosedRing(t,e,4);var i=e.getOrdinate(0,D.X)===e.getOrdinate(n-1,D.X)&&e.getOrdinate(0,D.Y)===e.getOrdinate(n-1,D.Y);return i?e:Ct.createClosedRing(t,e,n+1)},Ct.createClosedRing=function(t,e,n){var i=t.create(n,e.getDimension()),r=e.size();Ct.copy(e,0,i,0,r);for(var s=r;n>s;s++)Ct.copy(e,0,i,s,1);return i},h(St,B),e(St.prototype,{computeEnvelopeInternal:function(){return this.isEmpty()?new C:this.points.expandEnvelope(new C)},isRing:function(){return this.isClosed()&&this.isSimple()},getSortIndex:function(){return B.SORTINDEX_LINESTRING},getCoordinates:function(){return this.points.toCoordinateArray()},equalsExact:function(){if(2===arguments.length){var t=arguments[0],e=arguments[1];if(!this.isEquivalentClass(t))return!1;var n=t;if(this.points.size()!==n.points.size())return!1;for(var i=0;i0&&Ct.reverse(this.points),null}},getCoordinate:function(){return this.isEmpty()?null:this.points.getCoordinate(0)},getBoundaryDimension:function(){return this.isClosed()?lt.FALSE:0},isClosed:function(){return this.isEmpty()?!1:this.getCoordinateN(0).equals2D(this.getCoordinateN(this.getNumPoints()-1))},getEndPoint:function(){return this.isEmpty()?null:this.getPointN(this.getNumPoints()-1)},getDimension:function(){return 1},getLength:function(){return he.computeLength(this.points)},getNumPoints:function(){return this.points.size()},reverse:function(){var t=this.points.copy();Ct.reverse(t);var e=this.getFactory().createLineString(t);return e},compareToSameClass:function(){if(1===arguments.length){for(var t=arguments[0],e=t,n=0,i=0;n= 2)");this.points=t},isCoordinate:function(t){for(var e=0;en;n++){var i=t.getX(n);if(i!==e.getMinX()&&i!==e.getMaxX())return!1;var r=t.getY(n);if(r!==e.getMinY()&&r!==e.getMaxY())return!1}for(var s=t.getX(0),o=t.getY(0),n=1;4>=n;n++){var i=t.getX(n),r=t.getY(n),a=i!==s,u=r!==o;if(a===u)return!1;s=i,o=r}return!0},equalsExact:function(){if(2===arguments.length){var t=arguments[0],e=arguments[1];if(!this.isEquivalentClass(t))return!1;var n=t,i=this.shell,r=n.shell;if(!i.equalsExact(r,e))return!1;if(this.holes.length!==n.holes.length)return!1;for(var s=0;sl&&u>l;){var h=this.getInteriorRingN(l),c=s.getInteriorRingN(l),f=h.compareToSameClass(c,r);if(0!==f)return f;l++}return a>l?1:u>l?-1:0}},apply:function(){if(R(arguments[0],z)){var t=arguments[0];this.shell.apply(t);for(var e=0;e=1&&this.getCoordinateSequence().size()= 4)")},getGeometryType:function(){return"LinearRing"},copy:function(){return new bt(this.points.copy(),this.factory)},interfaces_:function(){return[]},getClass:function(){return bt}}),bt.MINIMUM_VALID_SIZE=4,bt.serialVersionUID=-0x3b229e262367a600,h(Ot,ft),e(Ot.prototype,{getSortIndex:function(){return B.SORTINDEX_MULTIPOLYGON},equalsExact:function(){if(2===arguments.length){var t=arguments[0],e=arguments[1];return this.isEquivalentClass(t)?ft.prototype.equalsExact.call(this,t,e):!1}return ft.prototype.equalsExact.apply(this,arguments)},getBoundaryDimension:function(){return 1},getDimension:function(){return 2},reverse:function(){for(var t=this.geometries.length,e=new Array(t).fill(null),n=0;n0?e.createPoint(n[0]):e.createPoint()}return t},interfaces_:function(){return[Mt]},getClass:function(){return At}}),e(Ft.prototype,{edit:function(t,e){return t instanceof bt?e.createLinearRing(this.edit(t.getCoordinateSequence(),t)):t instanceof St?e.createLineString(this.edit(t.getCoordinateSequence(),t)):t instanceof Lt?e.createPoint(this.edit(t.getCoordinateSequence(),t)):t},interfaces_:function(){return[Mt]},getClass:function(){return Ft}}),_t.NoOpGeometryOperation=Dt,_t.CoordinateOperation=At,_t.CoordinateSequenceOperation=Ft,e(Gt.prototype,{setOrdinate:function(t,e,n){switch(e){case D.X:this.coordinates[t].x=n;break;case D.Y:this.coordinates[t].y=n;break;case D.Z:this.coordinates[t].z=n;break;default:throw new i("invalid ordinateIndex")}},size:function(){return this.coordinates.length},getOrdinate:function(t,e){switch(e){case D.X:return this.coordinates[t].x;case D.Y:return this.coordinates[t].y;case D.Z:return this.coordinates[t].z}return r.NaN},getCoordinate:function(){if(1===arguments.length){var t=arguments[0];return this.coordinates[t]}if(2===arguments.length){var e=arguments[0],n=arguments[1];n.x=this.coordinates[e].x,n.y=this.coordinates[e].y,n.z=this.coordinates[e].z}},getCoordinateCopy:function(t){return new g(this.coordinates[t])},getDimension:function(){return this.dimension},getX:function(t){return this.coordinates[t].x},clone:function(){for(var t=new Array(this.size()).fill(null),e=0;e0){var t=new P(17*this.coordinates.length);t.append("("),t.append(this.coordinates[0]);for(var e=1;e3&&(i=3),2>i?new Gt(n):new Gt(n,i)}},interfaces_:function(){return[G,u]},getClass:function(){return qt}}),qt.instance=function(){return qt.instanceObject},qt.serialVersionUID=-0x38e49fa6cf6f2e00,qt.instanceObject=new qt;var no,io=Object.defineProperty,ro=zt({"delete":kt,has:Xt,get:Yt,set:Ht,keys:jt,values:Kt,entries:Zt,forEach:$t,clear:Wt}),so="undefined"!=typeof Map&&Map.prototype.values?Map:ro;te.prototype=new K,te.prototype.get=function(t){return this.map_.get(t)||null},te.prototype.put=function(t,e){return this.map_.set(t,e),e},te.prototype.values=function(){for(var t=new I,e=this.map_.values(),n=e.next();!n.done;)t.add(n.value),n=e.next();return t},te.prototype.entrySet=function(){var t=new J;return this.map_.entries().forEach(function(e){return t.add(e)}),t},te.prototype.size=function(){return this.map_.size()},e(ee.prototype,{equals:function(t){if(!(t instanceof ee))return!1;var e=t;return this.modelType===e.modelType&&this.scale===e.scale},compareTo:function(t){var e=t,n=this.getMaximumSignificantDigits(),i=e.getMaximumSignificantDigits();return new b(n).compareTo(new b(i))},getScale:function(){return this.scale},isFloating:function(){return this.modelType===ee.FLOATING||this.modelType===ee.FLOATING_SINGLE},getType:function(){return this.modelType},toString:function(){var t="UNKNOWN";return this.modelType===ee.FLOATING?t="Floating":this.modelType===ee.FLOATING_SINGLE?t="Floating-Single":this.modelType===ee.FIXED&&(t="Fixed (Scale="+this.getScale()+")"),t},makePrecise:function(){if("number"==typeof arguments[0]){var t=arguments[0];if(r.isNaN(t))return t;if(this.modelType===ee.FLOATING_SINGLE){var e=t;return e}return this.modelType===ee.FIXED?Math.round(t*this.scale)/this.scale:t}if(arguments[0]instanceof g){var n=arguments[0];if(this.modelType===ee.FLOATING)return null;n.x=this.makePrecise(n.x),n.y=this.makePrecise(n.y)}},getMaximumSignificantDigits:function(){var t=16;return this.modelType===ee.FLOATING?t=16:this.modelType===ee.FLOATING_SINGLE?t=6:this.modelType===ee.FIXED&&(t=1+Math.trunc(Math.ceil(Math.log(this.getScale())/Math.log(10)))),t},setScale:function(t){this.scale=Math.abs(t)},interfaces_:function(){return[u,s]},getClass:function(){return ee}}),ee.mostPrecise=function(t,e){return t.compareTo(e)>=0?t:e},e(ne.prototype,{readResolve:function(){return ne.nameToTypeMap.get(this.name)},toString:function(){return this.name},interfaces_:function(){return[u]},getClass:function(){return ne}}),ne.serialVersionUID=-552860263173159e4,ne.nameToTypeMap=new te,ee.Type=ne,ee.serialVersionUID=0x6bee6404e9a25c00,ee.FIXED=new ne("FIXED"),ee.FLOATING=new ne("FLOATING"),ee.FLOATING_SINGLE=new ne("FLOATING SINGLE"),ee.maximumPreciseValue=9007199254740992,e(ie.prototype,{toGeometry:function(t){return t.isNull()?this.createPoint(null):t.getMinX()===t.getMaxX()&&t.getMinY()===t.getMaxY()?this.createPoint(new g(t.getMinX(),t.getMinY())):t.getMinX()===t.getMaxX()||t.getMinY()===t.getMaxY()?this.createLineString([new g(t.getMinX(),t.getMinY()),new g(t.getMaxX(),t.getMaxY())]):this.createPolygon(this.createLinearRing([new g(t.getMinX(),t.getMinY()),new g(t.getMinX(),t.getMaxY()),new g(t.getMaxX(),t.getMaxY()),new g(t.getMaxX(),t.getMinY()),new g(t.getMinX(),t.getMinY())]),null)},createLineString:function(){if(0===arguments.length)return this.createLineString(this.getCoordinateSequenceFactory().create([]));if(1===arguments.length){if(arguments[0]instanceof Array){var t=arguments[0];return this.createLineString(null!==t?this.getCoordinateSequenceFactory().create(t):null)}if(R(arguments[0],D)){var e=arguments[0];return new St(e,this)}}},createMultiLineString:function(){if(0===arguments.length)return new gt(null,this);if(1===arguments.length){var t=arguments[0];return new gt(t,this)}},buildGeometry:function(t){for(var e=null,n=!1,i=!1,r=t.iterator();r.hasNext();){var s=r.next(),o=s.getClass();null===e&&(e=o),o!==e&&(n=!0),s.isGeometryCollectionOrDerived()&&(i=!0)}if(null===e)return this.createGeometryCollection();if(n||i)return this.createGeometryCollection(ie.toGeometryArray(t));var a=t.iterator().next(),u=t.size()>1;if(u){if(a instanceof Tt)return this.createMultiPolygon(ie.toPolygonArray(t));if(a instanceof St)return this.createMultiLineString(ie.toLineStringArray(t));if(a instanceof Lt)return this.createMultiPoint(ie.toPointArray(t));f.shouldNeverReachHere("Unhandled class: "+a.getClass().getName())}return a},createMultiPointFromCoords:function(t){return this.createMultiPoint(null!==t?this.getCoordinateSequenceFactory().create(t):null)},createPoint:function(){if(0===arguments.length)return this.createPoint(this.getCoordinateSequenceFactory().create([]));if(1===arguments.length){if(arguments[0]instanceof g){var t=arguments[0];return this.createPoint(null!==t?this.getCoordinateSequenceFactory().create([t]):null)}if(R(arguments[0],D)){var e=arguments[0];return new Lt(e,this)}}},getCoordinateSequenceFactory:function(){return this.coordinateSequenceFactory},createPolygon:function(){if(0===arguments.length)return new Tt(null,null,this);if(1===arguments.length){if(R(arguments[0],D)){var t=arguments[0];return this.createPolygon(this.createLinearRing(t))}if(arguments[0]instanceof Array){var e=arguments[0];return this.createPolygon(this.createLinearRing(e))}if(arguments[0]instanceof bt){var n=arguments[0];return this.createPolygon(n,null)}}else if(2===arguments.length){var i=arguments[0],r=arguments[1];return new Tt(i,r,this)}},getSRID:function(){return this.SRID},createGeometryCollection:function(){if(0===arguments.length)return new ft(null,this);if(1===arguments.length){var t=arguments[0];return new ft(t,this)}},createGeometry:function(t){var e=new _t(this);return e.edit(t,{edit:function(){if(2===arguments.length){var t=arguments[0];arguments[1];return this.coordinateSequenceFactory.create(t)}}})},getPrecisionModel:function(){return this.precisionModel},createLinearRing:function(){if(0===arguments.length)return this.createLinearRing(this.getCoordinateSequenceFactory().create([]));if(1===arguments.length){if(arguments[0]instanceof Array){var t=arguments[0];return this.createLinearRing(null!==t?this.getCoordinateSequenceFactory().create(t):null)}if(R(arguments[0],D)){var e=arguments[0];return new bt(e,this)}}},createMultiPolygon:function(){if(0===arguments.length)return new Ot(null,this);if(1===arguments.length){var t=arguments[0];return new Ot(t,this)}},createMultiPoint:function(){if(0===arguments.length)return new Pt(null,this);if(1===arguments.length){if(arguments[0]instanceof Array){var t=arguments[0];return new Pt(t,this)}if(arguments[0]instanceof Array){var e=arguments[0];return this.createMultiPoint(null!==e?this.getCoordinateSequenceFactory().create(e):null)}if(R(arguments[0],D)){var n=arguments[0];if(null===n)return this.createMultiPoint(new Array(0).fill(null));for(var i=new Array(n.size()).fill(null),r=0;rn;++n)e.push("("+ao.point.apply(this,[t.geometries[n]])+")");return e.join(",")},linestring:function(t){for(var e=[],n=0,i=t.points.coordinates.length;i>n;++n)e.push(ao.coordinate.apply(this,[t.points.coordinates[n]]));return e.join(",")},linearring:function(t){for(var e=[],n=0,i=t.points.coordinates.length;i>n;++n)e.push(ao.coordinate.apply(this,[t.points.coordinates[n]]));return e.join(",")},multilinestring:function(t){for(var e=[],n=0,i=t.geometries.length;i>n;++n)e.push("("+ao.linestring.apply(this,[t.geometries[n]])+")");return e.join(",")},polygon:function(t){var e=[];e.push("("+ao.linestring.apply(this,[t.shell])+")");for(var n=0,i=t.holes.length;i>n;++n)e.push("("+ao.linestring.apply(this,[t.holes[n]])+")");return e.join(",")},multipolygon:function(t){for(var e=[],n=0,i=t.geometries.length;i>n;++n)e.push("("+ao.polygon.apply(this,[t.geometries[n]])+")");return e.join(",")},geometrycollection:function(t){for(var e=[],n=0,i=t.geometries.length;i>n;++n)e.push(this.extractGeometry(t.geometries[n]));return e.join(",")}},uo={point:function(t){if(void 0===t)return this.geometryFactory.createPoint();var e=t.trim().split(oo.spaces);return this.geometryFactory.createPoint(new g(Number.parseFloat(e[0]),Number.parseFloat(e[1])))},multipoint:function(t){if(void 0===t)return this.geometryFactory.createMultiPoint();for(var e,n=t.trim().split(","),i=[],r=0,s=n.length;s>r;++r)e=n[r].replace(oo.trimParens,"$1"),i.push(uo.point.apply(this,[e]));return this.geometryFactory.createMultiPoint(i)},linestring:function(t){if(void 0===t)return this.geometryFactory.createLineString();for(var e,n=t.trim().split(","),i=[],r=0,s=n.length;s>r;++r)e=n[r].trim().split(oo.spaces),i.push(new g(Number.parseFloat(e[0]),Number.parseFloat(e[1])));return this.geometryFactory.createLineString(i)},linearring:function(t){if(void 0===t)return this.geometryFactory.createLinearRing();for(var e,n=t.trim().split(","),i=[],r=0,s=n.length;s>r;++r)e=n[r].trim().split(oo.spaces),i.push(new g(Number.parseFloat(e[0]),Number.parseFloat(e[1])));return this.geometryFactory.createLinearRing(i)},multilinestring:function(t){if(void 0===t)return this.geometryFactory.createMultiLineString();for(var e,n=t.trim().split(oo.parenComma),i=[],r=0,s=n.length;s>r;++r)e=n[r].replace(oo.trimParens,"$1"),i.push(uo.linestring.apply(this,[e]));return this.geometryFactory.createMultiLineString(i)},polygon:function(t){if(void 0===t)return this.geometryFactory.createPolygon();for(var e,n,i,r,s=t.trim().split(oo.parenComma),o=[],a=0,u=s.length;u>a;++a)e=s[a].replace(oo.trimParens,"$1"),n=uo.linestring.apply(this,[e]),i=this.geometryFactory.createLinearRing(n.points),0===a?r=i:o.push(i);return this.geometryFactory.createPolygon(r,o)},multipolygon:function(t){if(void 0===t)return this.geometryFactory.createMultiPolygon();for(var e,n=t.trim().split(oo.doubleParenComma),i=[],r=0,s=n.length;s>r;++r)e=n[r].replace(oo.trimParens,"$1"),i.push(uo.polygon.apply(this,[e]));return this.geometryFactory.createMultiPolygon(i)},geometrycollection:function(t){if(void 0===t)return this.geometryFactory.createGeometryCollection();t=t.replace(/,\s*([A-Za-z])/g,"|$1");for(var e=t.trim().split("|"),n=[],i=0,r=e.length;r>i;++i)n.push(this.read(e[i]));return this.geometryFactory.createGeometryCollection(n)}};e(se.prototype,{write:function(t){return this.parser.write(t)}}),e(se,{toLineString:function(t,e){if(2!==arguments.length)throw new Error("Not implemented");return"LINESTRING ( "+t.x+" "+t.y+", "+e.x+" "+e.y+" )"}}),e(oe.prototype,{getIndexAlongSegment:function(t,e){return this.computeIntLineIndex(),this.intLineIndex[t][e]},getTopologySummary:function(){var t=new P;return this.isEndPoint()&&t.append(" endpoint"),this._isProper&&t.append(" proper"),this.isCollinear()&&t.append(" collinear"),t.toString()},computeIntersection:function(t,e,n,i){this.inputLines[0][0]=t,this.inputLines[0][1]=e,this.inputLines[1][0]=n,this.inputLines[1][1]=i,this.result=this.computeIntersect(t,e,n,i)},getIntersectionNum:function(){return this.result},computeIntLineIndex:function(){if(0===arguments.length)null===this.intLineIndex&&(this.intLineIndex=Array(2).fill().map(function(){return Array(2)}),this.computeIntLineIndex(0),this.computeIntLineIndex(1));else if(1===arguments.length){var t=arguments[0],e=this.getEdgeDistance(t,0),n=this.getEdgeDistance(t,1);e>n?(this.intLineIndex[t][0]=0,this.intLineIndex[t][1]=1):(this.intLineIndex[t][0]=1,this.intLineIndex[t][1]=0)}},isProper:function(){return this.hasIntersection()&&this._isProper},setPrecisionModel:function(t){this.precisionModel=t},isInteriorIntersection:function(){if(0===arguments.length)return this.isInteriorIntersection(0)?!0:!!this.isInteriorIntersection(1);if(1===arguments.length){for(var t=arguments[0],e=0;er?i:r;else{var o=Math.abs(t.x-e.x),a=Math.abs(t.y-e.y);s=i>r?o:a,0!==s||t.equals(e)||(s=Math.max(o,a))}return f.isTrue(!(0===s&&!t.equals(e)),"Bad distance calculation"),s},oe.nonRobustComputeEdgeDistance=function(t,e,n){var i=t.x-e.x,r=t.y-e.y,s=Math.sqrt(i*i+r*r);return f.isTrue(!(0===s&&!t.equals(e)),"Invalid distance calculation"),s},oe.DONT_INTERSECT=0,oe.DO_INTERSECT=1,oe.COLLINEAR=2,oe.NO_INTERSECTION=0,oe.POINT_INTERSECTION=1,oe.COLLINEAR_INTERSECTION=2,h(ae,oe),e(ae.prototype,{isInSegmentEnvelopes:function(t){var e=new C(this.inputLines[0][0],this.inputLines[0][1]),n=new C(this.inputLines[1][0],this.inputLines[1][1]);return e.contains(t)&&n.contains(t)},computeIntersection:function(){if(3!==arguments.length)return oe.prototype.computeIntersection.apply(this,arguments);var t=arguments[0],e=arguments[1],n=arguments[2];return this._isProper=!1,C.intersects(e,n,t)&&0===he.orientationIndex(e,n,t)&&0===he.orientationIndex(n,e,t)?(this._isProper=!0,(t.equals(e)||t.equals(n))&&(this._isProper=!1),this.result=oe.POINT_INTERSECTION,null):void(this.result=oe.NO_INTERSECTION)},normalizeToMinimum:function(t,e,n,i,r){r.x=this.smallestInAbsValue(t.x,e.x,n.x,i.x),r.y=this.smallestInAbsValue(t.y,e.y,n.y,i.y),t.x-=r.x,t.y-=r.y,e.x-=r.x,e.y-=r.y,n.x-=r.x,n.y-=r.y,i.x-=r.x,i.y-=r.y},safeHCoordinateIntersection:function(t,e,n,i){var r=null;try{r=F.intersection(t,e,n,i)}catch(s){if(!(s instanceof w))throw s;r=ae.nearestEndpoint(t,e,n,i)}finally{}return r},intersection:function(t,e,n,i){var r=this.intersectionWithNormalization(t,e,n,i);return this.isInSegmentEnvelopes(r)||(r=new g(ae.nearestEndpoint(t,e,n,i))),null!==this.precisionModel&&this.precisionModel.makePrecise(r),r},smallestInAbsValue:function(t,e,n,i){var r=t,s=Math.abs(r);return Math.abs(e)1e-4&&A.out.println("Distance = "+r.distance(s))},intersectionWithNormalization:function(t,e,n,i){var r=new g(t),s=new g(e),o=new g(n),a=new g(i),u=new g;this.normalizeToEnvCentre(r,s,o,a,u);var l=this.safeHCoordinateIntersection(r,s,o,a);return l.x+=u.x,l.y+=u.y,l},computeCollinearIntersection:function(t,e,n,i){var r=C.intersects(t,e,n),s=C.intersects(t,e,i),o=C.intersects(n,i,t),a=C.intersects(n,i,e);return r&&s?(this.intPt[0]=n,this.intPt[1]=i,oe.COLLINEAR_INTERSECTION):o&&a?(this.intPt[0]=t,this.intPt[1]=e,oe.COLLINEAR_INTERSECTION):r&&o?(this.intPt[0]=n,this.intPt[1]=t,!n.equals(t)||s||a?oe.COLLINEAR_INTERSECTION:oe.POINT_INTERSECTION):r&&a?(this.intPt[0]=n,this.intPt[1]=e,!n.equals(e)||s||o?oe.COLLINEAR_INTERSECTION:oe.POINT_INTERSECTION):s&&o?(this.intPt[0]=i,this.intPt[1]=t,!i.equals(t)||r||a?oe.COLLINEAR_INTERSECTION:oe.POINT_INTERSECTION):s&&a?(this.intPt[0]=i,this.intPt[1]=e,!i.equals(e)||r||o?oe.COLLINEAR_INTERSECTION:oe.POINT_INTERSECTION):oe.NO_INTERSECTION},normalizeToEnvCentre:function(t,e,n,i,r){var s=t.xe.x?t.x:e.x,u=t.y>e.y?t.y:e.y,l=n.xi.x?n.x:i.x,f=n.y>i.y?n.y:i.y,g=s>l?s:l,d=c>a?a:c,p=o>h?o:h,v=f>u?u:f,m=(g+d)/2,y=(p+v)/2;r.x=m,r.y=y,t.x-=r.x,t.y-=r.y,e.x-=r.x,e.y-=r.y,n.x-=r.x,n.y-=r.y,i.x-=r.x,i.y-=r.y},computeIntersect:function(t,e,n,i){if(this._isProper=!1,!C.intersects(t,e,n,i))return oe.NO_INTERSECTION;var r=he.orientationIndex(t,e,n),s=he.orientationIndex(t,e,i);if(r>0&&s>0||0>r&&0>s)return oe.NO_INTERSECTION;var o=he.orientationIndex(n,i,t),a=he.orientationIndex(n,i,e);if(o>0&&a>0||0>o&&0>a)return oe.NO_INTERSECTION;var u=0===r&&0===s&&0===o&&0===a;return u?this.computeCollinearIntersection(t,e,n,i):(0===r||0===s||0===o||0===a?(this._isProper=!1,t.equals2D(n)||t.equals2D(i)?this.intPt[0]=t:e.equals2D(n)||e.equals2D(i)?this.intPt[0]=e:0===r?this.intPt[0]=new g(n):0===s?this.intPt[0]=new g(i):0===o?this.intPt[0]=new g(t):0===a&&(this.intPt[0]=new g(e))):(this._isProper=!0,this.intPt[0]=this.intersection(t,e,n,i)),oe.POINT_INTERSECTION)},interfaces_:function(){return[]},getClass:function(){return ae}}),ae.nearestEndpoint=function(t,e,n,i){var r=t,s=he.distancePointLine(t,n,i),o=he.distancePointLine(e,n,i);return s>o&&(s=o,r=e),o=he.distancePointLine(n,t,e),s>o&&(s=o,r=n),o=he.distancePointLine(i,t,e),s>o&&(s=o,r=i),r},e(ue.prototype,{interfaces_:function(){return[]},getClass:function(){return ue}}),ue.orientationIndex=function(t,e,n){var i=e.x-t.x,r=e.y-t.y,s=n.x-e.x,o=n.y-e.y;return ue.signOfDet2x2(i,r,s,o)},ue.signOfDet2x2=function(t,e,n,i){var r=null,s=null,o=null,a=0;if(r=1,0===t||0===i)return 0===e||0===n?0:e>0?n>0?-r:r:n>0?r:-r;if(0===e||0===n)return i>0?t>0?r:-r:t>0?-r:r;if(e>0?i>0?i>=e||(r=-r,s=t,t=n,n=s,s=e,e=i,i=s):-i>=e?(r=-r,n=-n,i=-i):(s=t,t=-n,n=s,s=e,e=-i,i=s):i>0?i>=-e?(r=-r,t=-t,e=-e):(s=-t,t=n,n=s,s=-e,e=i,i=s):e>=i?(t=-t,e=-e,n=-n,i=-i):(r=-r,s=-t,t=-n,n=s,s=-e,e=-i,i=s),t>0){if(!(n>0))return r;if(!(n>=t))return r}else{if(n>0)return-r;if(!(t>=n))return-r;r=-r,t=-t,n=-n}for(;;){if(a+=1,o=Math.floor(n/t),n-=o*t,i-=o*e,0>i)return-r;if(i>e)return r;if(t>n+n){if(i+i>e)return r}else{if(e>i+i)return-r;n=t-n,i=e-i,r=-r}if(0===i)return 0===n?0:-r;if(0===n)return r;if(o=Math.floor(t/n),t-=o*n,e-=o*i,0>e)return r;if(e>i)return-r;if(n>t+t){if(e+e>i)return-r}else{if(i>e+e)return r;t=n-t,e=i-e,r=-r}if(0===e)return 0===t?0:r;if(0===t)return-r}},e(le.prototype,{countSegment:function(t,e){if(t.xi&&(n=e.x,i=t.x),this.p.x>=n&&this.p.x<=i&&(this.isPointOnSegment=!0),null}if(t.y>this.p.y&&e.y<=this.p.y||e.y>this.p.y&&t.y<=this.p.y){var r=t.x-this.p.x,s=t.y-this.p.y,o=e.x-this.p.x,a=e.y-this.p.y,u=ue.signOfDet2x2(r,s,o,a);if(0===u)return this.isPointOnSegment=!0,null;s>a&&(u=-u),u>0&&this.crossingCount++}},isPointInPolygon:function(){return this.getLocation()!==L.EXTERIOR},getLocation:function(){return this.isPointOnSegment?L.BOUNDARY:this.crossingCount%2===1?L.INTERIOR:L.EXTERIOR},isOnSegment:function(){return this.isPointOnSegment},interfaces_:function(){return[]},getClass:function(){return le}}),le.locatePointInRing=function(){if(arguments[0]instanceof g&&R(arguments[1],D)){for(var t=arguments[0],e=arguments[1],n=new le(t),i=new g,r=new g,s=1;su)return 0;var l=new g,h=new g,c=new g;a.getCoordinate(0,h),a.getCoordinate(1,c);var n=h.x;c.x-=n;for(var e=0,i=1;u-1>i;i++)l.y=h.y,h.x=c.x,h.y=c.y,a.getCoordinate(i+1,c),c.x-=n,e+=h.x*(l.y-c.y);return e/2}},he.distanceLineLine=function(t,e,n,i){if(t.equals(e))return he.distancePointLine(t,n,i);if(n.equals(i))return he.distancePointLine(i,t,e);var r=!1;if(C.intersects(t,e,n,i)){var s=(e.x-t.x)*(i.y-n.y)-(e.y-t.y)*(i.x-n.x);if(0===s)r=!0;else{var o=(t.y-n.y)*(i.x-n.x)-(t.x-n.x)*(i.y-n.y),a=(t.y-n.y)*(e.x-t.x)-(t.x-n.x)*(e.y-t.y),u=a/s,l=o/s;(0>l||l>1||0>u||u>1)&&(r=!0)}}else r=!0;return r?T.min(he.distancePointLine(t,n,i),he.distancePointLine(e,n,i),he.distancePointLine(n,t,e),he.distancePointLine(i,t,e)):0},he.isPointInRing=function(t,e){return he.locatePointInRing(t,e)!==L.EXTERIOR},he.computeLength=function(t){var e=t.size();if(1>=e)return 0;var n=0,i=new g;t.getCoordinate(0,i);for(var r=i.x,s=i.y,o=1;e>o;o++){t.getCoordinate(o,i);var a=i.x,u=i.y,l=a-r,h=u-s;n+=Math.sqrt(l*l+h*h),r=a,s=u}return n},he.isCCW=function(t){var e=t.length-1;if(3>e)throw new i("Ring has fewer than 4 points, so orientation cannot be determined");for(var n=t[0],r=0,s=1;e>=s;s++){var o=t[s];o.y>n.y&&(n=o,r=s)}var a=r;do a-=1,0>a&&(a=e);while(t[a].equals2D(n)&&a!==r);var u=r;do u=(u+1)%e;while(t[u].equals2D(n)&&u!==r);var l=t[a],h=t[u];if(l.equals2D(n)||h.equals2D(n)||l.equals2D(h))return!1;var c=he.computeOrientation(l,n,h),f=!1;return f=0===c?l.x>h.x:c>0},he.locatePointInRing=function(t,e){return le.locatePointInRing(t,e)},he.distancePointLinePerpendicular=function(t,e,n){var i=(n.x-e.x)*(n.x-e.x)+(n.y-e.y)*(n.y-e.y),r=((e.y-t.y)*(n.x-e.x)-(e.x-t.x)*(n.y-e.y))/i;return Math.abs(r)*Math.sqrt(i)},he.computeOrientation=function(t,e,n){return he.orientationIndex(t,e,n)},he.distancePointLine=function(){if(2===arguments.length){var t=arguments[0],e=arguments[1];if(0===e.length)throw new i("Line array must contain at least one vertex");for(var n=t.distance(e[0]),r=0;rs&&(n=s)}return n}if(3===arguments.length){var o=arguments[0],a=arguments[1],u=arguments[2];if(a.x===u.x&&a.y===u.y)return o.distance(a);var l=(u.x-a.x)*(u.x-a.x)+(u.y-a.y)*(u.y-a.y),h=((o.x-a.x)*(u.x-a.x)+(o.y-a.y)*(u.y-a.y))/l;if(0>=h)return o.distance(a);if(h>=1)return o.distance(u);var c=((a.y-o.y)*(u.x-a.x)-(a.x-o.x)*(u.y-a.y))/l;return Math.abs(c)*Math.sqrt(l)}},he.isOnLine=function(t,e){for(var n=new ae,i=1;i=0&&n>=0?Math.max(e,n):0>=e&&0>=n?Math.max(e,n):0}if(arguments[0]instanceof g){var i=arguments[0];return he.orientationIndex(this.p0,this.p1,i)}},toGeometry:function(t){return t.createLineString([this.p0,this.p1])},isVertical:function(){return this.p0.x===this.p1.x},equals:function(t){if(!(t instanceof ce))return!1;var e=t;return this.p0.equals(e.p0)&&this.p1.equals(e.p1)},intersection:function(t){var e=new ae;return e.computeIntersection(this.p0,this.p1,t.p0,t.p1),e.hasIntersection()?e.getIntersection(0):null},project:function(){if(arguments[0]instanceof g){var t=arguments[0];if(t.equals(this.p0)||t.equals(this.p1))return new g(t);var e=this.projectionFactor(t),n=new g;return n.x=this.p0.x+e*(this.p1.x-this.p0.x),n.y=this.p0.y+e*(this.p1.y-this.p0.y),n}if(arguments[0]instanceof ce){var i=arguments[0],r=this.projectionFactor(i.p0),s=this.projectionFactor(i.p1);if(r>=1&&s>=1)return null;if(0>=r&&0>=s)return null;var o=this.project(i.p0);0>r&&(o=this.p0),r>1&&(o=this.p1);var a=this.project(i.p1);return 0>s&&(a=this.p0),s>1&&(a=this.p1),new ce(o,a)}},normalize:function(){this.p1.compareTo(this.p0)<0&&this.reverse()},angle:function(){return Math.atan2(this.p1.y-this.p0.y,this.p1.x-this.p0.x)},getCoordinate:function(t){return 0===t?this.p0:this.p1},distancePerpendicular:function(t){return he.distancePointLinePerpendicular(t,this.p0,this.p1)},minY:function(){return Math.min(this.p0.y,this.p1.y)},midPoint:function(){return ce.midPoint(this.p0,this.p1)},projectionFactor:function(t){if(t.equals(this.p0))return 0;if(t.equals(this.p1))return 1;var e=this.p1.x-this.p0.x,n=this.p1.y-this.p0.y,i=e*e+n*n;if(0>=i)return r.NaN;var s=((t.x-this.p0.x)*e+(t.y-this.p0.y)*n)/i;return s},closestPoints:function(t){var e=this.intersection(t);if(null!==e)return[e,e];var n=new Array(2).fill(null),i=r.MAX_VALUE,s=null,o=this.closestPoint(t.p0);i=o.distance(t.p0),n[0]=o,n[1]=t.p0;var a=this.closestPoint(t.p1);s=a.distance(t.p1),i>s&&(i=s,n[0]=a,n[1]=t.p1);var u=t.closestPoint(this.p0);s=u.distance(this.p0),i>s&&(i=s,n[0]=this.p0,n[1]=u);var l=t.closestPoint(this.p1);return s=l.distance(this.p1),i>s&&(i=s,n[0]=this.p1,n[1]=l),n},closestPoint:function(t){var e=this.projectionFactor(t);if(e>0&&1>e)return this.project(t);var n=this.p0.distance(t),i=this.p1.distance(t);return i>n?this.p0:this.p1},maxX:function(){return Math.max(this.p0.x,this.p1.x)},getLength:function(){return this.p0.distance(this.p1)},compareTo:function(t){var e=t,n=this.p0.compareTo(e.p0);return 0!==n?n:this.p1.compareTo(e.p1)},reverse:function(){var t=this.p0;this.p0=this.p1,this.p1=t},equalsTopo:function(t){return this.p0.equals(t.p0)&&this.p1.equals(t.p1)||this.p0.equals(t.p1)&&this.p1.equals(t.p0)},lineIntersection:function(t){try{var e=F.intersection(this.p0,this.p1,t.p0,t.p1);return e}catch(n){if(!(n instanceof w))throw n}finally{}return null},maxY:function(){return Math.max(this.p0.y,this.p1.y)},pointAlongOffset:function(t,e){var n=this.p0.x+t*(this.p1.x-this.p0.x),i=this.p0.y+t*(this.p1.y-this.p0.y),r=this.p1.x-this.p0.x,s=this.p1.y-this.p0.y,o=Math.sqrt(r*r+s*s),a=0,u=0;if(0!==e){if(0>=o)throw new IllegalStateException("Cannot compute offset from zero-length line segment");a=e*r/o,u=e*s/o}var l=n-u,h=i+a,c=new g(l,h);return c},setCoordinates:function(){if(1===arguments.length){var t=arguments[0];this.setCoordinates(t.p0,t.p1)}else if(2===arguments.length){var e=arguments[0],n=arguments[1];this.p0.x=e.x,this.p0.y=e.y,this.p1.x=n.x,this.p1.y=n.y}},segmentFraction:function(t){var e=this.projectionFactor(t);return 0>e?e=0:(e>1||r.isNaN(e))&&(e=1),e},toString:function(){return"LINESTRING( "+this.p0.x+" "+this.p0.y+", "+this.p1.x+" "+this.p1.y+")"},isHorizontal:function(){return this.p0.y===this.p1.y},distance:function(){if(arguments[0]instanceof ce){var t=arguments[0];return he.distanceLineLine(this.p0,this.p1,t.p0,t.p1)}if(arguments[0]instanceof g){var e=arguments[0];return he.distancePointLine(e,this.p0,this.p1)}},pointAlong:function(t){var e=new g;return e.x=this.p0.x+t*(this.p1.x-this.p0.x),e.y=this.p0.y+t*(this.p1.y-this.p0.y),e},hashCode:function(){var t=java.lang.Double.doubleToLongBits(this.p0.x);t^=31*java.lang.Double.doubleToLongBits(this.p0.y);var e=Math.trunc(t)^Math.trunc(t>>32),n=java.lang.Double.doubleToLongBits(this.p1.x);n^=31*java.lang.Double.doubleToLongBits(this.p1.y);var i=Math.trunc(n)^Math.trunc(n>>32);return e^i},interfaces_:function(){return[s,u]},getClass:function(){return ce}}),ce.midPoint=function(t,e){return new g((t.x+e.x)/2,(t.y+e.y)/2)},ce.serialVersionUID=0x2d2172135f411c00,e(fe.prototype,{isIntersects:function(){return!this.isDisjoint()},isCovers:function(){var t=fe.isTrue(this.matrix[L.INTERIOR][L.INTERIOR])||fe.isTrue(this.matrix[L.INTERIOR][L.BOUNDARY])||fe.isTrue(this.matrix[L.BOUNDARY][L.INTERIOR])||fe.isTrue(this.matrix[L.BOUNDARY][L.BOUNDARY]);return t&&this.matrix[L.EXTERIOR][L.INTERIOR]===lt.FALSE&&this.matrix[L.EXTERIOR][L.BOUNDARY]===lt.FALSE},isCoveredBy:function(){var t=fe.isTrue(this.matrix[L.INTERIOR][L.INTERIOR])||fe.isTrue(this.matrix[L.INTERIOR][L.BOUNDARY])||fe.isTrue(this.matrix[L.BOUNDARY][L.INTERIOR])||fe.isTrue(this.matrix[L.BOUNDARY][L.BOUNDARY]);return t&&this.matrix[L.INTERIOR][L.EXTERIOR]===lt.FALSE&&this.matrix[L.BOUNDARY][L.EXTERIOR]===lt.FALSE},set:function(){if(1===arguments.length)for(var t=arguments[0],e=0;e=0&&e>=0&&this.setAtLeast(t,e,n)},isWithin:function(){return fe.isTrue(this.matrix[L.INTERIOR][L.INTERIOR])&&this.matrix[L.INTERIOR][L.EXTERIOR]===lt.FALSE&&this.matrix[L.BOUNDARY][L.EXTERIOR]===lt.FALSE},isTouches:function(t,e){return t>e?this.isTouches(e,t):t===lt.A&&e===lt.A||t===lt.L&&e===lt.L||t===lt.L&&e===lt.A||t===lt.P&&e===lt.A||t===lt.P&&e===lt.L?this.matrix[L.INTERIOR][L.INTERIOR]===lt.FALSE&&(fe.isTrue(this.matrix[L.INTERIOR][L.BOUNDARY])||fe.isTrue(this.matrix[L.BOUNDARY][L.INTERIOR])||fe.isTrue(this.matrix[L.BOUNDARY][L.BOUNDARY])):!1},isOverlaps:function(t,e){return t===lt.P&&e===lt.P||t===lt.A&&e===lt.A?fe.isTrue(this.matrix[L.INTERIOR][L.INTERIOR])&&fe.isTrue(this.matrix[L.INTERIOR][L.EXTERIOR])&&fe.isTrue(this.matrix[L.EXTERIOR][L.INTERIOR]):t===lt.L&&e===lt.L?1===this.matrix[L.INTERIOR][L.INTERIOR]&&fe.isTrue(this.matrix[L.INTERIOR][L.EXTERIOR])&&fe.isTrue(this.matrix[L.EXTERIOR][L.INTERIOR]):!1},isEquals:function(t,e){return t!==e?!1:fe.isTrue(this.matrix[L.INTERIOR][L.INTERIOR])&&this.matrix[L.INTERIOR][L.EXTERIOR]===lt.FALSE&&this.matrix[L.BOUNDARY][L.EXTERIOR]===lt.FALSE&&this.matrix[L.EXTERIOR][L.INTERIOR]===lt.FALSE&&this.matrix[L.EXTERIOR][L.BOUNDARY]===lt.FALSE},toString:function(){for(var t=new P("123456789"),e=0;3>e;e++)for(var n=0;3>n;n++)t.setCharAt(3*e+n,lt.toDimensionSymbol(this.matrix[e][n]));return t.toString()},setAll:function(t){for(var e=0;3>e;e++)for(var n=0;3>n;n++)this.matrix[e][n]=t},get:function(t,e){return this.matrix[t][e]},transpose:function(){var t=this.matrix[1][0];return this.matrix[1][0]=this.matrix[0][1],this.matrix[0][1]=t,t=this.matrix[2][0],this.matrix[2][0]=this.matrix[0][2],this.matrix[0][2]=t,t=this.matrix[2][1],this.matrix[2][1]=this.matrix[1][2],this.matrix[1][2]=t,this},matches:function(t){if(9!==t.length)throw new i("Should be length 9: "+t);for(var e=0;3>e;e++)for(var n=0;3>n;n++)if(!fe.matches(this.matrix[e][n],t.charAt(3*e+n)))return!1;return!0},add:function(t){for(var e=0;3>e;e++)for(var n=0;3>n;n++)this.setAtLeast(e,n,t.get(e,n))},isDisjoint:function(){return this.matrix[L.INTERIOR][L.INTERIOR]===lt.FALSE&&this.matrix[L.INTERIOR][L.BOUNDARY]===lt.FALSE&&this.matrix[L.BOUNDARY][L.INTERIOR]===lt.FALSE&&this.matrix[L.BOUNDARY][L.BOUNDARY]===lt.FALSE},isCrosses:function(t,e){return t===lt.P&&e===lt.L||t===lt.P&&e===lt.A||t===lt.L&&e===lt.A?fe.isTrue(this.matrix[L.INTERIOR][L.INTERIOR])&&fe.isTrue(this.matrix[L.INTERIOR][L.EXTERIOR]):t===lt.L&&e===lt.P||t===lt.A&&e===lt.P||t===lt.A&&e===lt.L?fe.isTrue(this.matrix[L.INTERIOR][L.INTERIOR])&&fe.isTrue(this.matrix[L.EXTERIOR][L.INTERIOR]):t===lt.L&&e===lt.L?0===this.matrix[L.INTERIOR][L.INTERIOR]:!1},interfaces_:function(){return[o]},getClass:function(){return fe}}),fe.matches=function(){if(Number.isInteger(arguments[0])&&"string"==typeof arguments[1]){var t=arguments[0],e=arguments[1];return e===lt.SYM_DONTCARE?!0:e===lt.SYM_TRUE&&(t>=0||t===lt.TRUE)?!0:e===lt.SYM_FALSE&&t===lt.FALSE?!0:e===lt.SYM_P&&t===lt.P?!0:e===lt.SYM_L&&t===lt.L?!0:e===lt.SYM_A&&t===lt.A}if("string"==typeof arguments[0]&&"string"==typeof arguments[1]){var n=arguments[0],i=arguments[1],r=new fe(n);return r.matches(i)}},fe.isTrue=function(t){return t>=0||t===lt.TRUE};var lo=Object.freeze({Coordinate:g,CoordinateList:N,Envelope:C,LineSegment:ce,GeometryFactory:ie,Geometry:B,Point:Lt,LineString:St,LinearRing:bt,Polygon:Tt,GeometryCollection:ft,MultiPoint:Pt,MultiLineString:gt,MultiPolygon:Ot,Dimension:lt,IntersectionMatrix:fe});e(ge.prototype,{addPoint:function(t){this.ptCount+=1,this.ptCentSum.x+=t.x,this.ptCentSum.y+=t.y},setBasePoint:function(t){null===this.areaBasePt&&(this.areaBasePt=t)},addLineSegments:function(t){for(var e=0,n=0;n0&&this.addPoint(t[0])},addHole:function(t){for(var e=he.isCCW(t),n=0;n0)t.x=this.cg3.x/3/this.areasum2,t.y=this.cg3.y/3/this.areasum2;else if(this.totalLength>0)t.x=this.lineCentSum.x/this.totalLength,t.y=this.lineCentSum.y/this.totalLength;else{if(!(this.ptCount>0))return null;t.x=this.ptCentSum.x/this.ptCount,t.y=this.ptCentSum.y/this.ptCount}return t},addShell:function(t){t.length>0&&this.setBasePoint(t[0]);for(var e=!he.isCCW(t),n=0;nt||t>=this.size())throw new IndexOutOfBoundsException;return this.array_[t]},pe.prototype.push=function(t){return this.array_.push(t),t},pe.prototype.pop=function(t){if(0===this.array_.length)throw new de;return this.array_.pop()},pe.prototype.peek=function(){if(0===this.array_.length)throw new de;return this.array_[this.array_.length-1]},pe.prototype.empty=function(){return 0===this.array_.length},pe.prototype.isEmpty=function(){return this.empty()},pe.prototype.search=function(t){return this.array_.indexOf(t)},pe.prototype.size=function(){return this.array_.length},pe.prototype.toArray=function(){for(var t=[],e=0,n=this.array_.length;n>e;e++)t.push(this.array_[e]);return t},e(ve.prototype,{filter:function(t){this.treeSet.contains(t)||(this.list.add(t),this.treeSet.add(t))},getCoordinates:function(){var t=new Array(this.list.size()).fill(null);return this.list.toArray(t)},interfaces_:function(){return[z]},getClass:function(){return ve}}),ve.filterCoordinates=function(t){for(var e=new ve,n=0;n50&&(t=this.reduce(this.inputPts));var e=this.preSort(t),n=this.grahamScan(e),i=this.toCoordinateArray(n);return this.lineOrPolygon(i)},padArray3:function(t){for(var e=new Array(3).fill(null),n=0;ne[2].y&&(e[2]=t[i]),t[i].x+t[i].y>e[3].x+e[3].y&&(e[3]=t[i]),t[i].x>e[4].x&&(e[4]=t[i]),t[i].x-t[i].y>e[5].x-e[5].y&&(e[5]=t[i]),t[i].y0;)e=n.pop();e=n.push(e),e=n.push(t[i])}return e=n.push(t[0]),n},interfaces_:function(){return[]},getClass:function(){return me}}),me.extractCoordinates=function(t){var e=new ve;return t.apply(e),e.getCoordinates(); +},e(ye.prototype,{compare:function(t,e){var n=t,i=e;return ye.polarCompare(this.origin,n,i)},interfaces_:function(){return[a]},getClass:function(){return ye}}),ye.polarCompare=function(t,e,n){var i=e.x-t.x,r=e.y-t.y,s=n.x-t.x,o=n.y-t.y,a=he.computeOrientation(t,e,n);if(a===he.COUNTERCLOCKWISE)return 1;if(a===he.CLOCKWISE)return-1;var u=i*i+r*r,l=s*s+o*o;return l>u?-1:u>l?1:0},me.RadialComparator=ye,e(xe.prototype,{transformPoint:function(t,e){return this.factory.createPoint(this.transformCoordinates(t.getCoordinateSequence(),t))},transformPolygon:function(t,e){var n=!0,i=this.transformLinearRing(t.getExteriorRing(),t);null!==i&&i instanceof bt&&!i.isEmpty()||(n=!1);for(var r=new I,s=0;s0&&4>i&&!this.preserveType?this.factory.createLineString(n):this.factory.createLinearRing(n)},interfaces_:function(){return[]},getClass:function(){return xe}}),e(Ee.prototype,{snapVertices:function(t,e){for(var n=this._isClosed?t.size()-1:t.size(),i=0;n>i;i++){var r=t.get(i),s=this.findSnapForVertex(r,e);null!==s&&(t.set(i,new g(s)),0===i&&this._isClosed&&t.set(t.size()-1,new g(s)))}},findSnapForVertex:function(t,e){for(var n=0;ni;i++){var r=e[i],s=this.findSegmentIndexToSnap(r,t);s>=0&&t.add(s+1,new g(r),!1)}},findSegmentIndexToSnap:function(t,e){for(var n=r.MAX_VALUE,i=-1,s=0;so&&(n=o,i=s)}return i},setAllowSnappingToSourceVertices:function(t){this.allowSnappingToSourceVertices=t},interfaces_:function(){return[]},getClass:function(){return Ee}}),Ee.isClosed=function(t){return t.length<=1?!1:t[0].equals2D(t[t.length-1])},e(Ie.prototype,{snapTo:function(t,e){var n=this.extractTargetCoordinates(t),i=new Ne(e,n);return i.transform(this.srcGeom)},snapToSelf:function(t,e){var n=this.extractTargetCoordinates(this.srcGeom),i=new Ne(t,n,!0),r=i.transform(this.srcGeom),s=r;return e&&R(s,Rt)&&(s=r.buffer(0)),s},computeSnapTolerance:function(t){var e=this.computeMinimumSegmentLength(t),n=e/10;return n},extractTargetCoordinates:function(t){for(var e=new at,n=t.getCoordinates(),i=0;ii&&(e=i)}return e},interfaces_:function(){return[]},getClass:function(){return Ie}}),Ie.snap=function(t,e,n){var i=new Array(2).fill(null),r=new Ie(t);i[0]=r.snapTo(e,n);var s=new Ie(e);return i[1]=s.snapTo(i[0],n),i},Ie.computeOverlaySnapTolerance=function(){if(1===arguments.length){var t=arguments[0],e=Ie.computeSizeBasedSnapTolerance(t),n=t.getPrecisionModel();if(n.getType()===ee.FIXED){var i=1/n.getScale()*2/1.415;i>e&&(e=i)}return e}if(2===arguments.length){var r=arguments[0],s=arguments[1];return Math.min(Ie.computeOverlaySnapTolerance(r),Ie.computeOverlaySnapTolerance(s))}},Ie.computeSizeBasedSnapTolerance=function(t){var e=t.getEnvelopeInternal(),n=Math.min(e.getHeight(),e.getWidth()),i=n*Ie.SNAP_PRECISION_FACTOR;return i},Ie.snapToSelf=function(t,e,n){var i=new Ie(t);return i.snapToSelf(e,n)},Ie.SNAP_PRECISION_FACTOR=1e-9,h(Ne,xe),e(Ne.prototype,{snapLine:function(t,e){var n=new Ee(t,this.snapTolerance);return n.setAllowSnappingToSourceVertices(this.isSelfSnap),n.snapTo(e)},transformCoordinates:function(t,e){var n=t.toCoordinateArray(),i=this.snapLine(n,this.snapPts);return this.factory.getCoordinateSequenceFactory().create(i)},interfaces_:function(){return[]},getClass:function(){return Ne}}),e(Ce.prototype,{getCommon:function(){return r.longBitsToDouble(this.commonBits)},add:function(t){var e=r.doubleToLongBits(t);if(this.isFirst)return this.commonBits=e,this.commonSignExp=Ce.signExpBits(this.commonBits),this.isFirst=!1,null;var n=Ce.signExpBits(e);return n!==this.commonSignExp?(this.commonBits=0,null):(this.commonMantissaBitsCount=Ce.numCommonMostSigMantissaBits(this.commonBits,e),void(this.commonBits=Ce.zeroLowerBits(this.commonBits,64-(12+this.commonMantissaBitsCount))))},toString:function(){if(1===arguments.length){var t=arguments[0],e=r.longBitsToDouble(t),n=Long.toBinaryString(t),i="0000000000000000000000000000000000000000000000000000000000000000"+n,s=i.substring(i.length-64),o=s.substring(0,1)+" "+s.substring(1,12)+"(exp) "+s.substring(12)+" [ "+e+" ]";return o}},interfaces_:function(){return[]},getClass:function(){return Ce}}),Ce.getBit=function(t,e){var n=1<>52},Ce.zeroLowerBits=function(t,e){var n=(1<=0;i--){if(Ce.getBit(t,i)!==Ce.getBit(e,i))return n;n++}return 52},e(Se.prototype,{addCommonBits:function(t){var e=new Le(this.commonCoord);t.apply(e),t.geometryChanged()},removeCommonBits:function(t){if(0===this.commonCoord.x&&0===this.commonCoord.y)return t;var e=new g(this.commonCoord);e.x=-e.x,e.y=-e.y;var n=new Le(e);return t.apply(n),t.geometryChanged(),t},getCommonCoordinate:function(){return this.commonCoord},add:function(t){t.apply(this.ccFilter),this.commonCoord=this.ccFilter.getCommonCoordinate()},interfaces_:function(){return[]},getClass:function(){return Se}}),e(we.prototype,{filter:function(t){this.commonBitsX.add(t.x),this.commonBitsY.add(t.y)},getCommonCoordinate:function(){return new g(this.commonBitsX.getCommon(),this.commonBitsY.getCommon())},interfaces_:function(){return[z]},getClass:function(){return we}}),e(Le.prototype,{filter:function(t,e){var n=t.getOrdinate(e,0)+this.trans.x,i=t.getOrdinate(e,1)+this.trans.y;t.setOrdinate(e,0,n),t.setOrdinate(e,1,i)},isDone:function(){return!1},isGeometryChanged:function(){return!0},interfaces_:function(){return[ct]},getClass:function(){return Le}}),Se.CommonCoordinateFilter=we,Se.Translater=Le,e(Re.prototype,{next:function(){if(this.atStart)return this.atStart=!1,Re.isAtomic(this.parent)&&this.index++,this.parent;if(null!==this.subcollectionIterator){if(this.subcollectionIterator.hasNext())return this.subcollectionIterator.next();this.subcollectionIterator=null}if(this.index>=this.max)throw new x;var t=this.parent.getGeometryN(this.index++);return t instanceof ft?(this.subcollectionIterator=new Re(t),this.subcollectionIterator.next()):t},remove:function(){throw new UnsupportedOperationException(this.getClass().getName())},hasNext:function(){if(this.atStart)return!0;if(null!==this.subcollectionIterator){if(this.subcollectionIterator.hasNext())return!0;this.subcollectionIterator=null}return!(this.index>=this.max)},interfaces_:function(){return[p]},getClass:function(){return Re}}),Re.isAtomic=function(t){return!(t instanceof ft)},e(Te.prototype,{locateInternal:function(){if(arguments[0]instanceof g&&arguments[1]instanceof Tt){var t=arguments[0],e=arguments[1];if(e.isEmpty())return L.EXTERIOR;var n=e.getExteriorRing(),i=this.locateInPolygonRing(t,n);if(i===L.EXTERIOR)return L.EXTERIOR;if(i===L.BOUNDARY)return L.BOUNDARY;for(var r=0;r0||this.isIn?L.INTERIOR:L.EXTERIOR)},interfaces_:function(){return[]},getClass:function(){return Te}}),e(Pe.prototype,{interfaces_:function(){return[]},getClass:function(){return Pe}}),Pe.octant=function(){if("number"==typeof arguments[0]&&"number"==typeof arguments[1]){var t=arguments[0],e=arguments[1];if(0===t&&0===e)throw new i("Cannot compute the octant for point ( "+t+", "+e+" )");var n=Math.abs(t),r=Math.abs(e);return t>=0?e>=0?n>=r?0:1:n>=r?7:6:e>=0?n>=r?3:2:n>=r?4:5}if(arguments[0]instanceof g&&arguments[1]instanceof g){var s=arguments[0],o=arguments[1],a=o.x-s.x,u=o.y-s.y;if(0===a&&0===u)throw new i("Cannot compute the octant for two identical points "+s);return Pe.octant(a,u)}},e(be.prototype,{getCoordinates:function(){},size:function(){},getCoordinate:function(t){},isClosed:function(){},setData:function(t){},getData:function(){},interfaces_:function(){return[]},getClass:function(){return be}}),e(Oe.prototype,{getCoordinates:function(){return this.pts},size:function(){return this.pts.length},getCoordinate:function(t){return this.pts[t]},isClosed:function(){return this.pts[0].equals(this.pts[this.pts.length-1])},getSegmentOctant:function(t){return t===this.pts.length-1?-1:Pe.octant(this.getCoordinate(t),this.getCoordinate(t+1))},setData:function(t){this.data=t},getData:function(){return this.data},toString:function(){return se.toLineString(new Gt(this.pts))},interfaces_:function(){return[be]},getClass:function(){return Oe}}),e(_e.prototype,{getBounds:function(){},interfaces_:function(){return[]},getClass:function(){return _e}}),e(Me.prototype,{getItem:function(){return this.item},getBounds:function(){return this.bounds},interfaces_:function(){return[_e,u]},getClass:function(){return Me}}),e(De.prototype,{poll:function(){if(this.isEmpty())return null;var t=this.items.get(1);return this.items.set(1,this.items.get(this._size)),this._size-=1,this.reorder(1),t},size:function(){return this._size},reorder:function(t){for(var e=null,n=this.items.get(t);2*t<=this._size&&(e=2*t,e!==this._size&&this.items.get(e+1).compareTo(this.items.get(e))<0&&e++,this.items.get(e).compareTo(n)<0);t=e)this.items.set(t,this.items.get(e));this.items.set(t,n)},clear:function(){this._size=0,this.items.clear()},isEmpty:function(){return 0===this._size},add:function(t){this.items.add(null),this._size+=1;var e=this._size;for(this.items.set(0,t);t.compareTo(this.items.get(Math.trunc(e/2)))<0;e/=2)this.items.set(e,this.items.get(Math.trunc(e/2)));this.items.set(e,t)},interfaces_:function(){return[]},getClass:function(){return De}}),e(Ae.prototype,{visitItem:function(t){},interfaces_:function(){return[]},getClass:function(){return Ae}}),e(Fe.prototype,{insert:function(t,e){},remove:function(t,e){},query:function(){if(1===arguments.length){arguments[0]}else if(2===arguments.length){arguments[0],arguments[1]}},interfaces_:function(){return[]},getClass:function(){return Fe}}),e(Ge.prototype,{getLevel:function(){return this.level},size:function(){return this.childBoundables.size()},getChildBoundables:function(){return this.childBoundables},addChildBoundable:function(t){f.isTrue(null===this.bounds),this.childBoundables.add(t)},isEmpty:function(){return this.childBoundables.isEmpty()},getBounds:function(){return null===this.bounds&&(this.bounds=this.computeBounds()),this.bounds},interfaces_:function(){return[_e,u]},getClass:function(){return Ge}}),Ge.serialVersionUID=0x5a1e55ec41369800;var ho={reverseOrder:function(){return{compare:function(t,e){return e.compareTo(t)}}},min:function(t){return ho.sort(t),t.get(0)},sort:function(t,e){var n=t.toArray();e?ut.sort(n,e):ut.sort(n);for(var i=t.iterator(),r=0,s=n.length;s>r;r++)i.next(),i.set(n[r])},singletonList:function(t){var e=new I;return e.add(t),e}};e(qe.prototype,{expandToQueue:function(t,e){var n=qe.isComposite(this.boundable1),r=qe.isComposite(this.boundable2);if(n&&r)return qe.area(this.boundable1)>qe.area(this.boundable2)?(this.expand(this.boundable1,this.boundable2,t,e),null):(this.expand(this.boundable2,this.boundable1,t,e),null);if(n)return this.expand(this.boundable1,this.boundable2,t,e),null;if(r)return this.expand(this.boundable2,this.boundable1,t,e),null;throw new i("neither boundable is composite")},isLeaves:function(){return!(qe.isComposite(this.boundable1)||qe.isComposite(this.boundable2))},compareTo:function(t){var e=t;return this._distancee._distance?1:0},expand:function(t,e,n,i){for(var r=t.getChildBoundables(),s=r.iterator();s.hasNext();){var o=s.next(),a=new qe(o,e,this.itemDistance);a.getDistance()-2),i.getLevel()===n)return r.add(i),null;for(var s=i.getChildBoundables().iterator();s.hasNext();){var o=s.next();o instanceof Ge?this.boundablesAtLevel(n,o,r):(f.isTrue(o instanceof Me),-1===n&&r.add(o))}return null}},query:function(){if(1===arguments.length){var t=arguments[0];this.build();var e=new I;return this.isEmpty()?e:(this.getIntersectsOp().intersects(this.root.getBounds(),t)&&this.query(t,this.root,e),e)}if(2===arguments.length){var n=arguments[0],i=arguments[1];if(this.build(),this.isEmpty())return null;this.getIntersectsOp().intersects(this.root.getBounds(),n)&&this.query(n,this.root,i)}else if(3===arguments.length)if(R(arguments[2],Ae)&&arguments[0]instanceof Object&&arguments[1]instanceof Ge)for(var r=arguments[0],s=arguments[1],o=arguments[2],a=s.getChildBoundables(),u=0;ue&&(e=r)}}return e+1}},createParentBoundables:function(t,e){f.isTrue(!t.isEmpty());var n=new I;n.add(this.createNode(e));var i=new I(t);ho.sort(i,this.getComparator());for(var r=i.iterator();r.hasNext();){var s=r.next();this.lastNode(n).getChildBoundables().size()===this.getNodeCapacity()&&n.add(this.createNode(e)),this.lastNode(n).addChildBoundable(s)}return n},isEmpty:function(){return this.built?this.root.isEmpty():this.itemBoundables.isEmpty()},interfaces_:function(){return[u]},getClass:function(){return Be}}),Be.compareDoubles=function(t,e){return t>e?1:e>t?-1:0},Be.IntersectsOp=ze,Be.serialVersionUID=-0x35ef64c82d4c5400,Be.DEFAULT_NODE_CAPACITY=10,e(Ve.prototype,{distance:function(t,e){},interfaces_:function(){return[]},getClass:function(){return Ve}}),h(ke,Be),e(ke.prototype,{createParentBoundablesFromVerticalSlices:function(t,e){f.isTrue(t.length>0);for(var n=new I,i=0;is;s++){i[s]=new I;for(var o=0;r.hasNext()&&n>o;){var a=r.next();i[s].add(a),o++}}return i},query:function(){if(1===arguments.length){var t=arguments[0];return Be.prototype.query.call(this,t)}if(2===arguments.length){var e=arguments[0],n=arguments[1];Be.prototype.query.call(this,e,n)}else if(3===arguments.length)if(R(arguments[2],Ae)&&arguments[0]instanceof Object&&arguments[1]instanceof Ge){var i=arguments[0],r=arguments[1],s=arguments[2];Be.prototype.query.call(this,i,r,s)}else if(R(arguments[2],y)&&arguments[0]instanceof Object&&arguments[1]instanceof Ge){var o=arguments[0],a=arguments[1],u=arguments[2];Be.prototype.query.call(this,o,a,u)}},getComparator:function(){return ke.yComparator},createParentBoundablesFromVerticalSlice:function(t,e){return Be.prototype.createParentBoundables.call(this,t,e)},remove:function(){if(2===arguments.length){var t=arguments[0],e=arguments[1];return Be.prototype.remove.call(this,t,e)}return Be.prototype.remove.apply(this,arguments)},depth:function(){return 0===arguments.length?Be.prototype.depth.call(this):Be.prototype.depth.apply(this,arguments)},createParentBoundables:function(t,e){f.isTrue(!t.isEmpty());var n=Math.trunc(Math.ceil(t.size()/this.getNodeCapacity())),i=new I(t);ho.sort(i,ke.xComparator);var r=this.verticalSlices(i,Math.trunc(Math.ceil(Math.sqrt(n))));return this.createParentBoundablesFromVerticalSlices(r,e)},nearestNeighbour:function(){if(1===arguments.length){if(R(arguments[0],Ve)){var t=arguments[0],e=new qe(this.getRoot(),this.getRoot(),t);return this.nearestNeighbour(e)}if(arguments[0]instanceof qe){var n=arguments[0];return this.nearestNeighbour(n,r.POSITIVE_INFINITY)}}else if(2===arguments.length){if(arguments[0]instanceof ke&&R(arguments[1],Ve)){var i=arguments[0],s=arguments[1],e=new qe(this.getRoot(),i.getRoot(),s);return this.nearestNeighbour(e)}if(arguments[0]instanceof qe&&"number"==typeof arguments[1]){var o=arguments[0],a=arguments[1],u=a,l=null,h=new De;for(h.add(o);!h.isEmpty()&&u>0;){var c=h.poll(),f=c.getDistance();if(f>=u)break;c.isLeaves()?(u=f,l=c):c.expandToQueue(h,u)}return[l.getBoundable(0).getItem(),l.getBoundable(1).getItem()]}}else if(3===arguments.length){var g=arguments[0],d=arguments[1],p=arguments[2],v=new Me(g,d),e=new qe(this.getRoot(),v,p);return this.nearestNeighbour(e)[0]}},interfaces_:function(){return[Fe,u]},getClass:function(){return ke}}),ke.centreX=function(t){return ke.avg(t.getMinX(),t.getMaxX())},ke.avg=function(t,e){return(t+e)/2},ke.centreY=function(t){return ke.avg(t.getMinY(),t.getMaxY())},h(Ye,Ge),e(Ye.prototype,{computeBounds:function(){for(var t=null,e=this.getChildBoundables().iterator();e.hasNext();){var n=e.next();null===t?t=new C(n.getBounds()):t.expandToInclude(n.getBounds())}return t},interfaces_:function(){return[]},getClass:function(){return Ye}}),ke.STRtreeNode=Ye,ke.serialVersionUID=0x39920f7d5f261e0,ke.xComparator={interfaces_:function(){return[a]},compare:function(t,e){return Be.compareDoubles(ke.centreX(t.getBounds()),ke.centreX(e.getBounds()))}},ke.yComparator={interfaces_:function(){return[a]},compare:function(t,e){return Be.compareDoubles(ke.centreY(t.getBounds()),ke.centreY(e.getBounds()))}},ke.intersectsOp={interfaces_:function(){return[IntersectsOp]},intersects:function(t,e){return t.intersects(e)}},ke.DEFAULT_NODE_CAPACITY=10,e(Ue.prototype,{interfaces_:function(){return[]},getClass:function(){return Ue}}),Ue.relativeSign=function(t,e){return e>t?-1:t>e?1:0},Ue.compare=function(t,e,n){if(e.equals2D(n))return 0;var i=Ue.relativeSign(e.x,n.x),r=Ue.relativeSign(e.y,n.y);switch(t){case 0:return Ue.compareValue(i,r);case 1:return Ue.compareValue(r,i);case 2:return Ue.compareValue(r,-i);case 3:return Ue.compareValue(-i,r);case 4:return Ue.compareValue(-i,-r);case 5:return Ue.compareValue(-r,-i);case 6:return Ue.compareValue(-r,i);case 7:return Ue.compareValue(i,-r)}return f.shouldNeverReachHere("invalid octant value"),0},Ue.compareValue=function(t,e){return 0>t?-1:t>0?1:0>e?-1:e>0?1:0},e(Xe.prototype,{getCoordinate:function(){return this.coord},print:function(t){t.print(this.coord),t.print(" seg # = "+this.segmentIndex)},compareTo:function(t){var e=t;return this.segmentIndexe.segmentIndex?1:this.coord.equals2D(e.coord)?0:Ue.compare(this.segmentOctant,this.coord,e.coord)},isEndPoint:function(t){return 0!==this.segmentIndex||this._isInterior?this.segmentIndex===t:!0},isInterior:function(){return this._isInterior},interfaces_:function(){return[s]},getClass:function(){return Xe}}),e(He.prototype,{getSplitCoordinates:function(){var t=new N;this.addEndpoints();for(var e=this.iterator(),n=e.next();e.hasNext();){var i=e.next();this.addEdgeCoordinates(n,i,t),n=i}return t.toCoordinateArray()},addCollapsedNodes:function(){var t=new I;this.findCollapsesFromInsertedNodes(t),this.findCollapsesFromExistingVertices(t);for(var e=t.iterator();e.hasNext();){var n=e.next().intValue();this.add(this.edge.getCoordinate(n),n)}},print:function(t){t.println("Intersections:");for(var e=this.iterator();e.hasNext();){var n=e.next();n.print(t)}},findCollapsesFromExistingVertices:function(t){for(var e=0;ethis.currNode.segmentIndex,null)},remove:function(){throw new UnsupportedOperationException(this.getClass().getName())},hasNext:function(){return null!==this.nextNode},readNextNode:function(){this.nodeIt.hasNext()?this.nextNode=this.nodeIt.next():this.nextNode=null},interfaces_:function(){return[p]},getClass:function(){return We}}),e(je.prototype,{addIntersection:function(t,e){},interfaces_:function(){return[be]},getClass:function(){return je}}),e(Ke.prototype,{getCoordinates:function(){return this.pts},size:function(){return this.pts.length},getCoordinate:function(t){return this.pts[t]},isClosed:function(){return this.pts[0].equals(this.pts[this.pts.length-1])},getSegmentOctant:function(t){return t===this.pts.length-1?-1:this.safeOctant(this.getCoordinate(t),this.getCoordinate(t+1))},setData:function(t){this.data=t},safeOctant:function(t,e){return t.equals2D(e)?0:Pe.octant(t,e)},getData:function(){return this.data},addIntersection:function(){if(2===arguments.length){var t=arguments[0],e=arguments[1];this.addIntersectionNode(t,e)}else if(4===arguments.length){var n=arguments[0],i=arguments[1],r=(arguments[2],arguments[3]),s=new g(n.getIntersection(r));this.addIntersection(s,i)}},toString:function(){return se.toLineString(new Gt(this.pts))},getNodeList:function(){return this.nodeList},addIntersectionNode:function(t,e){var n=e,i=n+1;if(ie&&this.computeSelect(t,e,o,i),n>o&&this.computeSelect(t,o,n,i)},getCoordinates:function(){for(var t=new Array(this.end-this.start+1).fill(null),e=0,n=this.start;n<=this.end;n++)t[e++]=this.pts[n];return t},computeOverlaps:function(t,e){this.computeOverlapsInternal(this.start,this.end,t,t.start,t.end,e)},setId:function(t){this.id=t},select:function(t,e){this.computeSelect(t,this.start,this.end,e)},getEnvelope:function(){if(null===this.env){var t=this.pts[this.start],e=this.pts[this.end];this.env=new C(t,e)}return this.env},getEndIndex:function(){return this.end},getStartIndex:function(){return this.start},getContext:function(){return this.context},getId:function(){return this.id},computeOverlapsInternal:function(t,e,n,i,r,s){var o=this.pts[t],a=this.pts[e],u=n.pts[i],l=n.pts[r];if(e-t===1&&r-i===1)return s.overlap(this,t,n,i),null;if(s.tempEnv1.init(o,a),s.tempEnv2.init(u,l),!s.tempEnv1.intersects(s.tempEnv2))return null;var h=Math.trunc((t+e)/2),c=Math.trunc((i+r)/2);h>t&&(c>i&&this.computeOverlapsInternal(t,h,n,i,c,s),r>c&&this.computeOverlapsInternal(t,h,n,c,r,s)),e>h&&(c>i&&this.computeOverlapsInternal(h,e,n,i,c,s),r>c&&this.computeOverlapsInternal(h,e,n,c,r,s))},interfaces_:function(){return[]},getClass:function(){return Qe}}),e(Je.prototype,{interfaces_:function(){return[]},getClass:function(){return Je}}),Je.isNorthern=function(t){return t===Je.NE||t===Je.NW},Je.isOpposite=function(t,e){if(t===e)return!1;var n=(t-e+4)%4;return 2===n},Je.commonHalfPlane=function(t,e){if(t===e)return t;var n=(t-e+4)%4;if(2===n)return-1;var i=e>t?t:e,r=t>e?t:e;return 0===i&&3===r?3:i},Je.isInHalfPlane=function(t,e){return e===Je.SE?t===Je.SE||t===Je.SW:t===e||t===e+1},Je.quadrant=function(){if("number"==typeof arguments[0]&&"number"==typeof arguments[1]){var t=arguments[0],e=arguments[1];if(0===t&&0===e)throw new i("Cannot compute the quadrant for point ( "+t+", "+e+" )");return t>=0?e>=0?Je.NE:Je.SE:e>=0?Je.NW:Je.SW}if(arguments[0]instanceof g&&arguments[1]instanceof g){var n=arguments[0],r=arguments[1];if(r.x===n.x&&r.y===n.y)throw new i("Cannot compute the quadrant for two identical points "+n);return r.x>=n.x?r.y>=n.y?Je.NE:Je.SE:r.y>=n.y?Je.NW:Je.SW}},Je.NE=0,Je.NW=1,Je.SW=2,Je.SE=3,e($e.prototype,{interfaces_:function(){return[]},getClass:function(){return $e}}),$e.getChainStartIndices=function(t){var e=0,n=new I;n.add(new b(e));do{var i=$e.findChainEnd(t,e);n.add(new b(i)),e=i}while(e=t.length-1)return t.length-1;for(var i=Je.quadrant(t[n],t[n+1]),r=e+1;rn.getId()&&(n.computeOverlaps(s,t),this.nOverlaps++),this.segInt.isDone())return null}},interfaces_:function(){return[]},getClass:function(){return nn}}),h(rn,Ze),e(rn.prototype,{overlap:function(){if(4!==arguments.length)return Ze.prototype.overlap.apply(this,arguments);var t=arguments[0],e=arguments[1],n=arguments[2],i=arguments[3],r=t.getContext(),s=n.getContext();this.si.processIntersections(r,e,s,i)},interfaces_:function(){return[]},getClass:function(){return rn}}),nn.SegmentOverlapAction=rn,h(sn,l),e(sn.prototype,{getCoordinate:function(){return this.pt},interfaces_:function(){return[]},getClass:function(){return sn}}),sn.msgWithCoord=function(t,e){return null!==e?t+" [ "+e+" ]":t},e(on.prototype,{processIntersections:function(t,e,n,i){},isDone:function(){},interfaces_:function(){return[]},getClass:function(){return on}}),e(an.prototype,{getInteriorIntersection:function(){return this.interiorIntersection},setCheckEndSegmentsOnly:function(t){this.isCheckEndSegmentsOnly=t},getIntersectionSegments:function(){return this.intSegments},count:function(){return this.intersectionCount},getIntersections:function(){return this.intersections},setFindAllIntersections:function(t){this.findAllIntersections=t},setKeepIntersections:function(t){this.keepIntersections=t},processIntersections:function(t,e,n,i){if(!this.findAllIntersections&&this.hasIntersection())return null;if(t===n&&e===i)return null;if(this.isCheckEndSegmentsOnly){var r=this.isEndSegment(t,e)||this.isEndSegment(n,i);if(!r)return null}var s=t.getCoordinates()[e],o=t.getCoordinates()[e+1],a=n.getCoordinates()[i],u=n.getCoordinates()[i+1];this.li.computeIntersection(s,o,a,u),this.li.hasIntersection()&&this.li.isInteriorIntersection()&&(this.intSegments=new Array(4).fill(null),this.intSegments[0]=s,this.intSegments[1]=o,this.intSegments[2]=a,this.intSegments[3]=u,this.interiorIntersection=this.li.getIntersection(0),this.keepIntersections&&this.intersections.add(this.interiorIntersection),this.intersectionCount++)},isEndSegment:function(t,e){return 0===e?!0:e>=t.size()-2},hasIntersection:function(){return null!==this.interiorIntersection},isDone:function(){return this.findAllIntersections?!1:null!==this.interiorIntersection},interfaces_:function(){return[on]},getClass:function(){return an}}),an.createAllIntersectionsFinder=function(t){var e=new an(t);return e.setFindAllIntersections(!0),e},an.createAnyIntersectionFinder=function(t){return new an(t)},an.createIntersectionCounter=function(t){var e=new an(t);return e.setFindAllIntersections(!0),e.setKeepIntersections(!1),e},e(un.prototype,{execute:function(){return null!==this.segInt?null:void this.checkInteriorIntersections()},getIntersections:function(){return this.segInt.getIntersections()},isValid:function(){return this.execute(),this._isValid},setFindAllIntersections:function(t){this.findAllIntersections=t},checkInteriorIntersections:function(){this._isValid=!0,this.segInt=new an(this.li),this.segInt.setFindAllIntersections(this.findAllIntersections);var t=new nn;return t.setSegmentIntersector(this.segInt),t.computeNodes(this.segStrings),this.segInt.hasIntersection()?(this._isValid=!1,null):void 0},checkValid:function(){if(this.execute(),!this._isValid)throw new sn(this.getErrorMessage(),this.segInt.getInteriorIntersection())},getErrorMessage:function(){if(this._isValid)return"no intersections found";var t=this.segInt.getIntersectionSegments();return"found non-noded intersection between "+se.toLineString(t[0],t[1])+" and "+se.toLineString(t[2],t[3])},interfaces_:function(){return[]},getClass:function(){return un}}),un.computeIntersections=function(t){var e=new un(t);return e.setFindAllIntersections(!0),e.isValid(),e.getIntersections()},e(ln.prototype,{checkValid:function(){this.nv.checkValid()},interfaces_:function(){return[]},getClass:function(){return ln}}),ln.toSegmentStrings=function(t){for(var e=new I,n=t.iterator();n.hasNext();){var i=n.next();e.add(new Oe(i.getCoordinates(),i))}return e},ln.checkValid=function(t){var e=new ln(t);e.checkValid()},e(hn.prototype,{map:function(t){for(var e=new I,n=0;nthis.location.length){var e=new Array(3).fill(null);e[cn.ON]=this.location[cn.ON],e[cn.LEFT]=L.NONE,e[cn.RIGHT]=L.NONE,this.location=e}for(var n=0;n1&&t.append(L.toLocationSymbol(this.location[cn.LEFT])),t.append(L.toLocationSymbol(this.location[cn.ON])),this.location.length>1&&t.append(L.toLocationSymbol(this.location[cn.RIGHT])),t.toString()},setLocations:function(t,e,n){this.location[cn.ON]=t,this.location[cn.LEFT]=e,this.location[cn.RIGHT]=n},get:function(t){return t1},isAnyNull:function(){for(var t=0;te;e++)null===this.elt[e]&&null!==t.elt[e]?this.elt[e]=new fn(t.elt[e]):this.elt[e].merge(t.elt[e])},flip:function(){this.elt[0].flip(),this.elt[1].flip()},getLocation:function(){if(1===arguments.length){var t=arguments[0];return this.elt[t].get(cn.ON)}if(2===arguments.length){var e=arguments[0],n=arguments[1];return this.elt[e].get(n)}},toString:function(){var t=new P;return null!==this.elt[0]&&(t.append("A:"),t.append(this.elt[0].toString())),null!==this.elt[1]&&(t.append(" B:"),t.append(this.elt[1].toString())),t.toString()},isArea:function(){if(0===arguments.length)return this.elt[0].isArea()||this.elt[1].isArea();if(1===arguments.length){var t=arguments[0];return this.elt[t].isArea()}},isAnyNull:function(t){return this.elt[t].isAnyNull()},setLocation:function(){if(2===arguments.length){var t=arguments[0],e=arguments[1];this.elt[t].setLocation(cn.ON,e)}else if(3===arguments.length){var n=arguments[0],i=arguments[1],r=arguments[2];this.elt[n].setLocation(i,r)}},isEqualOnSide:function(t,e){return this.elt[0].isEqualOnSide(t.elt[0],e)&&this.elt[1].isEqualOnSide(t.elt[1],e)},allPositionsEqual:function(t,e){return this.elt[t].allPositionsEqual(e)},toLine:function(t){this.elt[t].isArea()&&(this.elt[t]=new fn(this.elt[t].location[0]))},interfaces_:function(){return[]},getClass:function(){return gn}}),gn.toLineLabel=function(t){for(var e=new gn(L.NONE),n=0;2>n;n++)e.setLocation(n,t.getLocation(n));return e},e(dn.prototype,{computeRing:function(){if(null!==this.ring)return null;for(var t=new Array(this.pts.size()).fill(null),e=0;ethis.maxNodeDegree&&(this.maxNodeDegree=n),t=this.getNext(t)}while(t!==this.startDe);this.maxNodeDegree*=2},addPoints:function(t,e,n){var i=t.getCoordinates();if(e){var r=1;n&&(r=0);for(var s=r;s=0;s--)this.pts.add(i[s])}},isHole:function(){return this._isHole},setInResult:function(){var t=this.startDe;do t.getEdge().setInResult(!0),t=t.getNext();while(t!==this.startDe)},containsPoint:function(t){var e=this.getLinearRing(),n=e.getEnvelopeInternal();if(!n.contains(t))return!1;if(!he.isPointInRing(t,e.getCoordinates()))return!1;for(var i=this.holes.iterator();i.hasNext();){var r=i.next();if(r.containsPoint(t))return!1}return!0},addHole:function(t){this.holes.add(t)},isShell:function(){return null===this.shell},getLabel:function(){return this.label},getEdges:function(){return this.edges},getMaxNodeDegree:function(){return this.maxNodeDegree<0&&this.computeMaxNodeDegree(),this.maxNodeDegree},getShell:function(){return this.shell},mergeLabel:function(){if(1===arguments.length){var t=arguments[0];this.mergeLabel(t,0),this.mergeLabel(t,1)}else if(2===arguments.length){var e=arguments[0],n=arguments[1],i=e.getLocation(n,cn.RIGHT);if(i===L.NONE)return null;if(this.label.getLocation(n)===L.NONE)return this.label.setLocation(n,i),null}},setShell:function(t){this.shell=t,null!==t&&t.addHole(this)},toPolygon:function(t){for(var e=new Array(this.holes.size()).fill(null),n=0;n=2,"found partial label"),this.computeIM(t)},isInResult:function(){return this._isInResult},isVisited:function(){return this._isVisited},interfaces_:function(){return[]},getClass:function(){return mn}}),h(yn,mn),e(yn.prototype,{isIncidentEdgeInResult:function(){for(var t=this.getEdges().getEdges().iterator();t.hasNext();){var e=t.next();if(e.getEdge().isInResult())return!0}return!1},isIsolated:function(){return 1===this.label.getGeometryCount()},getCoordinate:function(){return this.coord},print:function(t){t.println("node "+this.coord+" lbl: "+this.label)},computeIM:function(t){},computeMergedLocation:function(t,e){var n=L.NONE;if(n=this.label.getLocation(e),!t.isNull(e)){var i=t.getLocation(e);n!==L.BOUNDARY&&(n=i)}return n},setLabel:function(){if(2!==arguments.length)return mn.prototype.setLabel.apply(this,arguments);var t=arguments[0],e=arguments[1];null===this.label?this.label=new gn(t,e):this.label.setLocation(t,e)},getEdges:function(){return this.edges},mergeLabel:function(){if(arguments[0]instanceof yn){var t=arguments[0];this.mergeLabel(t.label)}else if(arguments[0]instanceof gn)for(var e=arguments[0],n=0;2>n;n++){var i=this.computeMergedLocation(e,n),r=this.label.getLocation(n);r===L.NONE&&this.label.setLocation(n,i)}},add:function(t){this.edges.insert(t),t.setNode(this)},setLabelBoundary:function(t){if(null===this.label)return null;var e=L.NONE;null!==this.label&&(e=this.label.getLocation(t));var n=null;switch(e){case L.BOUNDARY:n=L.INTERIOR;break;case L.INTERIOR:n=L.BOUNDARY;break;default:n=L.BOUNDARY}this.label.setLocation(t,n)},interfaces_:function(){return[]},getClass:function(){return yn}}),e(xn.prototype,{find:function(t){return this.nodeMap.get(t)},addNode:function(){if(arguments[0]instanceof g){var t=arguments[0],e=this.nodeMap.get(t);return null===e&&(e=this.nodeFact.createNode(t),this.nodeMap.put(t,e)),e}if(arguments[0]instanceof yn){var n=arguments[0],e=this.nodeMap.get(n.getCoordinate());return null===e?(this.nodeMap.put(n.getCoordinate(),n),n):(e.mergeLabel(n),e)}},print:function(t){for(var e=this.iterator();e.hasNext();){var n=e.next();n.print(t)}},iterator:function(){return this.nodeMap.values().iterator()},values:function(){return this.nodeMap.values()},getBoundaryNodes:function(t){for(var e=new I,n=this.iterator();n.hasNext();){var i=n.next();i.getLabel().getLocation(t)===L.BOUNDARY&&e.add(i)}return e},add:function(t){var e=t.getCoordinate(),n=this.addNode(e);n.add(t)},interfaces_:function(){return[]},getClass:function(){return xn}}),e(En.prototype,{compareDirection:function(t){return this.dx===t.dx&&this.dy===t.dy?0:this.quadrant>t.quadrant?1:this.quadrantt;t++)this.label.isArea(t)&&this.label.getLocation(t,cn.LEFT)===L.INTERIOR&&this.label.getLocation(t,cn.RIGHT)===L.INTERIOR||(Bo=!1);return Bo},setNextMin:function(t){this.nextMin=t},print:function(t){En.prototype.print.call(this,t),t.print(" "+this.depth[cn.LEFT]+"/"+this.depth[cn.RIGHT]),t.print(" ("+this.getDepthDelta()+")"),this._isInResult&&t.print(" inResult")},setMinEdgeRing:function(t){this.minEdgeRing=t},isLineEdge:function(){var t=this.label.isLine(0)||this.label.isLine(1),e=!this.label.isArea(0)||this.label.allPositionsEqual(0,L.EXTERIOR),n=!this.label.isArea(1)||this.label.allPositionsEqual(1,L.EXTERIOR);return t&&e&&n},setEdgeRing:function(t){this.edgeRing=t},getMinEdgeRing:function(){return this.minEdgeRing},getDepthDelta:function(){var t=this.edge.getDepthDelta();return this._isForward||(t=-t),t},setInResult:function(t){this._isInResult=t},getSym:function(){return this.sym},isForward:function(){return this._isForward},getEdge:function(){return this.edge},printEdge:function(t){this.print(t),t.print(" "),this._isForward?this.edge.print(t):this.edge.printReverse(t)},setSym:function(t){this.sym=t},setVisitedEdge:function(t){this.setVisited(t),this.sym.setVisited(t)},setEdgeDepths:function(t,e){var n=this.getEdge().getDepthDelta();this._isForward||(n=-n);var i=1;t===cn.LEFT&&(i=-1);var r=cn.opposite(t),s=n*i,o=e+s;this.setDepth(t,e),this.setDepth(r,o)},getEdgeRing:function(){return this.edgeRing},isInResult:function(){return this._isInResult},setNext:function(t){this.next=t},isVisited:function(){return this._isVisited},interfaces_:function(){return[]},getClass:function(){return In}}),In.depthFactor=function(t,e){return t===L.EXTERIOR&&e===L.INTERIOR?1:t===L.INTERIOR&&e===L.EXTERIOR?-1:0},e(Nn.prototype,{createNode:function(t){return new yn(t,null)},interfaces_:function(){return[]},getClass:function(){return Nn}}),e(Cn.prototype,{printEdges:function(t){t.println("Edges:");for(var e=0;e2){s.linkDirectedEdgesForMinimalEdgeRings();var o=s.buildMinimalRings(),a=this.findShell(o);null!==a?(this.placePolygonHoles(a,o),e.add(a)):n.addAll(o)}else i.add(s)}return i},containsPoint:function(t){for(var e=this.shellList.iterator();e.hasNext();){var n=e.next();if(n.containsPoint(t))return!0}return!1},buildMaximalEdgeRings:function(t){for(var e=new I,n=t.iterator();n.hasNext();){var i=n.next();if(i.isInResult()&&i.getLabel().isArea()&&null===i.getEdgeRing()){var r=new vn(i,this.geometryFactory);e.add(r),r.setInResult()}}return e},placePolygonHoles:function(t,e){for(var n=e.iterator();n.hasNext();){var i=n.next();i.isHole()&&i.setShell(t)}},getPolygons:function(){var t=this.computePolygons(this.shellList);return t},findEdgeRingContaining:function(t,e){for(var n=t.getLinearRing(),i=n.getEnvelopeInternal(),r=n.getCoordinateN(0),s=null,o=null,a=e.iterator();a.hasNext();){var u=a.next(),l=u.getLinearRing(),h=l.getEnvelopeInternal();null!==s&&(o=s.getLinearRing().getEnvelopeInternal());var c=!1;h.contains(i)&&he.isPointInRing(r,l.getCoordinates())&&(c=!0),c&&(null===s||o.contains(h))&&(s=u)}return s},findShell:function(t){for(var e=0,n=null,i=t.iterator();i.hasNext();){var r=i.next();r.isHole()||(n=r,e++)}return f.isTrue(1>=e,"found two shells in MinimalEdgeRing list"),n},add:function(){if(1===arguments.length){var t=arguments[0];this.add(t.getEdgeEnds(),t.getNodes())}else if(2===arguments.length){var e=arguments[0],n=arguments[1];Cn.linkResultDirectedEdges(n);var i=this.buildMaximalEdgeRings(e),r=new I,s=this.buildMinimalEdgeRings(i,this.shellList,r);this.sortShellsAndHoles(s,this.shellList,r),this.placeFreeHoles(this.shellList,r)}},interfaces_:function(){return[]},getClass:function(){return Sn}}),e(wn.prototype,{collectLines:function(t){for(var e=this.op.getGraph().getEdgeEnds().iterator();e.hasNext();){var n=e.next();this.collectLineEdge(n,t,this.lineEdgesList),this.collectBoundaryTouchEdge(n,t,this.lineEdgesList)}},labelIsolatedLine:function(t,e){var n=this.ptLocator.locate(t.getCoordinate(),this.op.getArgGeometry(e));t.getLabel().setLocation(e,n)},build:function(t){return this.findCoveredLineEdges(),this.collectLines(t),this.buildLines(t),this.resultLineList},collectLineEdge:function(t,e,n){var i=t.getLabel(),r=t.getEdge();t.isLineEdge()&&(t.isVisited()||!ii.isResultOfOp(i,e)||r.isCovered()||(n.add(r),t.setVisitedEdge(!0)))},findCoveredLineEdges:function(){for(var t=this.op.getGraph().getNodes().iterator();t.hasNext();){var e=t.next();e.getEdges().findCoveredLineEdges()}for(var n=this.op.getGraph().getEdgeEnds().iterator();n.hasNext();){var i=n.next(),r=i.getEdge();if(i.isLineEdge()&&!r.isCoveredSet()){var s=this.op.isCoveredByA(i.getCoordinate());r.setCovered(s)}}},labelIsolatedLines:function(t){for(var e=t.iterator();e.hasNext();){var n=e.next(),i=n.getLabel();n.isIsolated()&&(i.isNull(0)?this.labelIsolatedLine(n,0):this.labelIsolatedLine(n,1))}},buildLines:function(t){for(var e=this.lineEdgesList.iterator();e.hasNext();){var n=e.next(),i=(n.getLabel(),this.geometryFactory.createLineString(n.getCoordinates()));this.resultLineList.add(i),n.setInResult(!0)}},collectBoundaryTouchEdge:function(t,e,n){var i=t.getLabel();return t.isLineEdge()?null:t.isVisited()?null:t.isInteriorAreaEdge()?null:t.getEdge().isInResult()?null:(f.isTrue(!(t.isInResult()||t.getSym().isInResult())||!t.getEdge().isInResult()),void(ii.isResultOfOp(i,e)&&e===ii.INTERSECTION&&(n.add(t.getEdge()),t.setVisitedEdge(!0))))},interfaces_:function(){return[]},getClass:function(){return wn}}),e(Ln.prototype,{filterCoveredNodeToPoint:function(t){var e=t.getCoordinate();if(!this.op.isCoveredByLA(e)){var n=this.geometryFactory.createPoint(e);this.resultPointList.add(n)}},extractNonCoveredResultNodes:function(t){for(var e=this.op.getGraph().getNodes().iterator();e.hasNext();){var n=e.next();if(!(n.isInResult()||n.isIncidentEdgeInResult()||0!==n.getEdges().getDegree()&&t!==ii.INTERSECTION)){var i=n.getLabel();ii.isResultOfOp(i,t)&&this.filterCoveredNodeToPoint(n)}}},build:function(t){return this.extractNonCoveredResultNodes(t),this.resultPointList},interfaces_:function(){return[]},getClass:function(){return Ln}}),e(Rn.prototype,{locate:function(t){},interfaces_:function(){return[]},getClass:function(){return Rn}}),e(Tn.prototype,{locate:function(t){return Tn.locate(t,this.geom)},interfaces_:function(){return[Rn]},getClass:function(){return Tn}}),Tn.isPointInRing=function(t,e){return e.getEnvelopeInternal().intersects(t)?he.isPointInRing(t,e.getCoordinates()):!1},Tn.containsPointInPolygon=function(t,e){if(e.isEmpty())return!1;var n=e.getExteriorRing();if(!Tn.isPointInRing(t,n))return!1;for(var i=0;is;s++)r.isLine(s)&&r.getLocation(s)===L.BOUNDARY&&(e[s]=!0);for(var n=this.iterator();n.hasNext();)for(var i=n.next(),r=i.getLabel(),s=0;2>s;s++)if(r.isAnyNull(s)){var o=L.NONE;if(e[s])o=L.EXTERIOR;else{var a=i.getCoordinate();o=this.getLocation(s,a,t)}r.setAllLocationsIfNull(s,o)}},getDegree:function(){return this.edgeMap.size()},insertEdgeEnd:function(t,e){this.edgeMap.put(t,e),this.edgeList=null},interfaces_:function(){return[]},getClass:function(){return Pn}}),h(bn,Pn),e(bn.prototype,{linkResultDirectedEdges:function(){this.getResultAreaEdges();for(var t=null,e=null,n=this.SCANNING_FOR_INCOMING,i=0;ie)return null;var n=t.get(0);if(1===e)return n;var i=t.get(e-1),r=n.getQuadrant(),s=i.getQuadrant();if(Je.isNorthern(r)&&Je.isNorthern(s))return n;if(!Je.isNorthern(r)&&!Je.isNorthern(s))return i;return 0!==n.getDy()?n:0!==i.getDy()?i:(f.shouldNeverReachHere("found two horizontal edges incident on node"),null)},print:function(t){A.out.println("DirectedEdgeStar: "+this.getCoordinate());for(var e=this.iterator();e.hasNext();){var n=e.next();t.print("out "),n.print(t),t.println(),t.print("in "),n.getSym().print(t),t.println()}},getResultAreaEdges:function(){if(null!==this.resultAreaEdgeList)return this.resultAreaEdgeList;this.resultAreaEdgeList=new I;for(var t=this.iterator();t.hasNext();){var e=t.next();(e.isInResult()||e.getSym().isInResult())&&this.resultAreaEdgeList.add(e)}return this.resultAreaEdgeList},updateLabelling:function(t){for(var e=this.iterator();e.hasNext();){var n=e.next(),i=n.getLabel();i.setAllLocationsIfNull(0,t.getLocation(0)),i.setAllLocationsIfNull(1,t.getLocation(1))}},linkAllDirectedEdges:function(){this.getEdges();for(var t=null,e=null,n=this.edgeList.size()-1;n>=0;n--){var i=this.edgeList.get(n),r=i.getSym();null===e&&(e=r),null!==t&&r.setNext(t),t=i}e.setNext(t)},computeDepths:function(){if(1===arguments.length){var t=arguments[0],e=this.findIndex(t),n=(t.getLabel(),t.getDepth(cn.LEFT)),i=t.getDepth(cn.RIGHT),r=this.computeDepths(e+1,this.edgeList.size(),n),s=this.computeDepths(0,e,r);if(s!==i)throw new sn("depth mismatch at "+t.getCoordinate())}else if(3===arguments.length){for(var o=arguments[0],a=arguments[1],u=arguments[2],l=u,h=o;a>h;h++){var c=this.edgeList.get(h);c.getLabel();c.setEdgeDepths(cn.RIGHT,l),l=c.getDepth(cn.LEFT)}return l}},mergeSymLabels:function(){for(var t=this.iterator();t.hasNext();){var e=t.next(),n=e.getLabel();n.merge(e.getSym().getLabel())}},linkMinimalDirectedEdges:function(t){for(var e=null,n=null,i=this.SCANNING_FOR_INCOMING,r=this.resultAreaEdgeList.size()-1;r>=0;r--){var s=this.resultAreaEdgeList.get(r),o=s.getSym();switch(null===e&&s.getEdgeRing()===t&&(e=s),i){case this.SCANNING_FOR_INCOMING:if(o.getEdgeRing()!==t)continue;n=o,i=this.LINKING_TO_OUTGOING;break;case this.LINKING_TO_OUTGOING:if(s.getEdgeRing()!==t)continue;n.setNextMin(s),i=this.SCANNING_FOR_INCOMING}}i===this.LINKING_TO_OUTGOING&&(f.isTrue(null!==e,"found null for first outgoing dirEdge"),f.isTrue(e.getEdgeRing()===t,"unable to link last incoming dirEdge"),n.setNextMin(e))},getOutgoingDegree:function(){if(0===arguments.length){for(var t=0,e=this.iterator();e.hasNext();){var n=e.next();n.isInResult()&&t++}return t}if(1===arguments.length){for(var i=arguments[0],t=0,e=this.iterator();e.hasNext();){var n=e.next();n.getEdgeRing()===i&&t++}return t}},getLabel:function(){return this.label},findCoveredLineEdges:function(){for(var t=L.NONE,e=this.iterator();e.hasNext();){var n=e.next(),i=n.getSym();if(!n.isLineEdge()){if(n.isInResult()){t=L.INTERIOR;break}if(i.isInResult()){t=L.EXTERIOR;break}}}if(t===L.NONE)return null;for(var r=t,e=this.iterator();e.hasNext();){var n=e.next(),i=n.getSym();n.isLineEdge()?n.getEdge().setCovered(r===L.INTERIOR):(n.isInResult()&&(r=L.EXTERIOR),i.isInResult()&&(r=L.INTERIOR))}},computeLabelling:function(t){Pn.prototype.computeLabelling.call(this,t),this.label=new gn(L.NONE);for(var e=this.iterator();e.hasNext();)for(var n=e.next(),i=n.getEdge(),r=i.getLabel(),s=0;2>s;s++){var o=r.getLocation(s);o!==L.INTERIOR&&o!==L.BOUNDARY||this.label.setLocation(s,L.INTERIOR)}},interfaces_:function(){return[]},getClass:function(){return bn}}),h(On,Nn),e(On.prototype,{createNode:function(t){return new yn(t,new bn)},interfaces_:function(){return[]},getClass:function(){return On}}),e(_n.prototype,{computeIntersections:function(t,e){this.mce.computeIntersectsForChain(this.chainIndex,t.mce,t.chainIndex,e)},interfaces_:function(){return[]},getClass:function(){return _n}}),e(Mn.prototype,{isDelete:function(){return this.eventType===Mn.DELETE},setDeleteEventIndex:function(t){this.deleteEventIndex=t},getObject:function(){return this.obj},compareTo:function(t){var e=t;return this.xValuee.xValue?1:this.eventTypee.eventType?1:0},getInsertEvent:function(){return this.insertEvent},isInsert:function(){return this.eventType===Mn.INSERT},isSameLabel:function(t){return null===this.label?!1:this.label===t.label},getDeleteEventIndex:function(){return this.deleteEventIndex},interfaces_:function(){return[s]},getClass:function(){return Mn}}),Mn.INSERT=1,Mn.DELETE=2,e(Dn.prototype,{interfaces_:function(){return[]},getClass:function(){return Dn}}),e(An.prototype,{isTrivialIntersection:function(t,e,n,i){if(t===n&&1===this.li.getIntersectionNum()){if(An.isAdjacentSegments(e,i))return!0;if(t.isClosed()){var r=t.getNumPoints()-1;if(0===e&&i===r||0===i&&e===r)return!0}}return!1},getProperIntersectionPoint:function(){return this.properIntersectionPoint},setIsDoneIfProperInt:function(t){this.isDoneWhenProperInt=t},hasProperInteriorIntersection:function(){return this.hasProperInterior},isBoundaryPointInternal:function(t,e){for(var n=e.iterator();n.hasNext();){var i=n.next(),r=i.getCoordinate();if(t.isIntersection(r))return!0}return!1},hasProperIntersection:function(){return this.hasProper},hasIntersection:function(){return this._hasIntersection},isDone:function(){return this._isDone},isBoundaryPoint:function(t,e){return null===e?!1:this.isBoundaryPointInternal(t,e[0])?!0:!!this.isBoundaryPointInternal(t,e[1])},setBoundaryNodes:function(t,e){this.bdyNodes=new Array(2).fill(null),this.bdyNodes[0]=t,this.bdyNodes[1]=e},addIntersections:function(t,e,n,i){if(t===n&&e===i)return null;this.numTests++;var r=t.getCoordinates()[e],s=t.getCoordinates()[e+1],o=n.getCoordinates()[i],a=n.getCoordinates()[i+1];this.li.computeIntersection(r,s,o,a),this.li.hasIntersection()&&(this.recordIsolated&&(t.setIsolated(!1),n.setIsolated(!1)),this.numIntersections++,this.isTrivialIntersection(t,e,n,i)||(this._hasIntersection=!0,!this.includeProper&&this.li.isProper()||(t.addIntersections(this.li,e,0),n.addIntersections(this.li,i,1)),this.li.isProper()&&(this.properIntersectionPoint=this.li.getIntersection(0).copy(),this.hasProper=!0,this.isDoneWhenProperInt&&(this._isDone=!0),this.isBoundaryPoint(this.li,this.bdyNodes)||(this.hasProperInterior=!0))))},interfaces_:function(){return[]},getClass:function(){return An}}),An.isAdjacentSegments=function(t,e){return 1===Math.abs(t-e)},h(Fn,Dn),e(Fn.prototype,{prepareEvents:function(){ho.sort(this.events);for(var t=0;ts;s++){var o=this.events.get(s);if(o.isInsert()){var a=o.getObject();n.isSameLabel(o)||(r.computeIntersections(a,i),this.nOverlaps++)}}},addEdges:function(){if(1===arguments.length)for(var t=arguments[0],e=t.iterator();e.hasNext();){var n=e.next();this.addEdge(n,n)}else if(2===arguments.length)for(var i=arguments[0],r=arguments[1],e=i.iterator();e.hasNext();){var n=e.next();this.addEdge(n,r)}},interfaces_:function(){return[]},getClass:function(){return Fn}}),e(Gn.prototype,{getMin:function(){return this.min},intersects:function(t,e){return!(this.min>e||this.maxr?-1:r>s?1:0},interfaces_:function(){return[a]},getClass:function(){return qn}}),Gn.NodeComparator=qn,h(Bn,Gn),e(Bn.prototype,{query:function(t,e,n){return this.intersects(t,e)?void n.visitItem(this.item):null},interfaces_:function(){return[]},getClass:function(){return Bn}}),h(zn,Gn),e(zn.prototype,{buildExtent:function(t,e){this.min=Math.min(t.min,e.min),this.max=Math.max(t.max,e.max)},query:function(t,e,n){return this.intersects(t,e)?(null!==this.node1&&this.node1.query(t,e,n),void(null!==this.node2&&this.node2.query(t,e,n))):null},interfaces_:function(){return[]},getClass:function(){return zn}}),e(Vn.prototype,{buildTree:function(){ho.sort(this.leaves,new IntervalRTreeNode.NodeComparator);for(var t=this.leaves,e=null,n=new I;;){if(this.buildLevel(t,n),1===n.size())return n.get(0);e=t,t=n,n=e}},insert:function(t,e,n){if(null!==this.root)throw new IllegalStateException("Index cannot be added to once it has been queried");this.leaves.add(new Bn(t,e,n))},query:function(t,e,n){this.init(),this.root.query(t,e,n)},buildRoot:function(){return null!==this.root?null:void(this.root=this.buildTree())},printNode:function(t){A.out.println(se.toLineString(new g(t.min,this.level),new g(t.max,this.level)))},init:function(){return null!==this.root?null:void this.buildRoot()},buildLevel:function(t,e){this.level++,e.clear();for(var n=0;n0||!e.coord.equals2D(i);r||n--;var s=new Array(n).fill(null),o=0;s[o++]=new g(t.coord);for(var a=t.segmentIndex+1;a<=e.segmentIndex;a++)s[o++]=this.edge.pts[a];return r&&(s[o]=e.coord),new Jn(s,new gn(this.edge.label))},add:function(t,e,n){var i=new Wn(t,e,n),r=this.nodeMap.get(i);return null!==r?r:(this.nodeMap.put(i,i),i)},isIntersection:function(t){for(var e=this.iterator();e.hasNext();){var n=e.next();if(n.coord.equals(t))return!0}return!1},interfaces_:function(){return[]},getClass:function(){return jn}}),e(Kn.prototype,{getChainStartIndices:function(t){var e=0,n=new I;n.add(new b(e));do{var i=this.findChainEnd(t,e);n.add(new b(i)),e=i}while(en?e:n},getMinX:function(t){var e=this.pts[this.startIndex[t]].x,n=this.pts[this.startIndex[t+1]].x;return n>e?e:n},computeIntersectsForChain:function(){if(4===arguments.length){var t=arguments[0],e=arguments[1],n=arguments[2],i=arguments[3];this.computeIntersectsForChain(this.startIndex[t],this.startIndex[t+1],e,e.startIndex[n],e.startIndex[n+1],i)}else if(6===arguments.length){var r=arguments[0],s=arguments[1],o=arguments[2],a=arguments[3],u=arguments[4],l=arguments[5],h=this.pts[r],c=this.pts[s],f=o.pts[a],g=o.pts[u];if(s-r===1&&u-a===1)return l.addIntersections(this.e,r,o.e,a),null;if(this.env1.init(h,c),this.env2.init(f,g),!this.env1.intersects(this.env2))return null;var d=Math.trunc((r+s)/2),p=Math.trunc((a+u)/2);d>r&&(p>a&&this.computeIntersectsForChain(r,d,o,a,p,l),u>p&&this.computeIntersectsForChain(r,d,o,p,u,l)),s>d&&(p>a&&this.computeIntersectsForChain(d,s,o,a,p,l),u>p&&this.computeIntersectsForChain(d,s,o,p,u,l))}},getStartIndexes:function(){return this.startIndex},computeIntersects:function(t,e){for(var n=0;nt;t++)for(var e=0;3>e;e++)if(this.depth[t][e]!==Qn.NULL_VALUE)return!1;return!0}if(1===arguments.length){var n=arguments[0];return this.depth[n][1]===Qn.NULL_VALUE}if(2===arguments.length){var i=arguments[0],r=arguments[1];return this.depth[i][r]===Qn.NULL_VALUE}},normalize:function(){for(var t=0;2>t;t++)if(!this.isNull(t)){var e=this.depth[t][1];this.depth[t][2]e&&(e=0);for(var n=1;3>n;n++){var i=0;this.depth[t][n]>e&&(i=1),this.depth[t][n]=i}}},getDelta:function(t){return this.depth[t][cn.RIGHT]-this.depth[t][cn.LEFT]},getLocation:function(t,e){return this.depth[t][e]<=0?L.EXTERIOR:L.INTERIOR},toString:function(){return"A: "+this.depth[0][1]+","+this.depth[0][2]+" B: "+this.depth[1][1]+","+this.depth[1][2]},add:function(){if(1===arguments.length)for(var t=arguments[0],e=0;2>e;e++)for(var n=1;3>n;n++){var i=t.getLocation(e,n);i!==L.EXTERIOR&&i!==L.INTERIOR||(this.isNull(e,n)?this.depth[e][n]=Qn.depthAtLocation(i):this.depth[e][n]+=Qn.depthAtLocation(i))}else if(3===arguments.length){var r=arguments[0],s=arguments[1],o=arguments[2];o===L.INTERIOR&&this.depth[r][s]++}},interfaces_:function(){return[]},getClass:function(){return Qn}}),Qn.depthAtLocation=function(t){return t===L.EXTERIOR?0:t===L.INTERIOR?1:Qn.NULL_VALUE},Qn.NULL_VALUE=-1,h(Jn,mn),e(Jn.prototype,{getDepth:function(){return this.depth},getCollapsedEdge:function(){var t=new Array(2).fill(null);t[0]=this.pts[0],t[1]=this.pts[1];var e=new Jn(t,gn.toLineLabel(this.label));return e},isIsolated:function(){return this._isIsolated},getCoordinates:function(){return this.pts},setIsolated:function(t){this._isIsolated=t},setName:function(t){this.name=t},equals:function(t){if(!(t instanceof Jn))return!1;var e=t;if(this.pts.length!==e.pts.length)return!1;for(var n=!0,i=!0,r=this.pts.length,s=0;s0?this.pts[0]:null;if(1===arguments.length){var t=arguments[0];return this.pts[t]}},print:function(t){t.print("edge "+this.name+": "),t.print("LINESTRING (");for(var e=0;e0&&t.print(","),t.print(this.pts[e].x+" "+this.pts[e].y);t.print(") "+this.label+" "+this.depthDelta)},computeIM:function(t){Jn.updateIM(this.label,t)},isCollapsed:function(){return this.label.isArea()?3!==this.pts.length?!1:!!this.pts[0].equals(this.pts[2]):!1},isClosed:function(){return this.pts[0].equals(this.pts[this.pts.length-1])},getMaximumSegmentIndex:function(){return this.pts.length-1},getDepthDelta:function(){return this.depthDelta},getNumPoints:function(){return this.pts.length},printReverse:function(t){t.print("edge "+this.name+": ");for(var e=this.pts.length-1;e>=0;e--)t.print(this.pts[e]+" ");t.println("")},getMonotoneChainEdge:function(){return null===this.mce&&(this.mce=new Zn(this)),this.mce},getEnvelope:function(){if(null===this.env){this.env=new C;for(var t=0;t0&&t.append(","),t.append(this.pts[e].x+" "+this.pts[e].y);return t.append(") "+this.label+" "+this.depthDelta),t.toString()},isPointwiseEqual:function(t){if(this.pts.length!==t.pts.length)return!1;for(var e=0;e=2,"found LineString with single point"),this.insertBoundaryPoint(this.argIndex,e[0]),this.insertBoundaryPoint(this.argIndex,e[e.length-1])},getInvalidPoint:function(){return this.invalidPoint},getBoundaryPoints:function(){for(var t=this.getBoundaryNodes(),e=new Array(t.size()).fill(null),n=0,i=t.iterator();i.hasNext();){var r=i.next();e[n++]=r.getCoordinate().copy()}return e},getBoundaryNodes:function(){return null===this.boundaryNodes&&(this.boundaryNodes=this.nodes.getBoundaryNodes(this.argIndex)),this.boundaryNodes},addSelfIntersectionNode:function(t,e,n){return this.isBoundaryNode(t,e)?null:void(n===L.BOUNDARY&&this.useBoundaryDeterminationRule?this.insertBoundaryPoint(t,e):this.insertPoint(t,e,n))},addPolygonRing:function(t,e,n){if(t.isEmpty())return null;var i=H.removeRepeatedPoints(t.getCoordinates());if(i.length<4)return this._hasTooFewPoints=!0,this.invalidPoint=i[0],null;var r=e,s=n;he.isCCW(i)&&(r=n,s=e);var o=new Jn(i,new gn(this.argIndex,L.BOUNDARY,r,s));this.lineEdgeMap.put(t,o),this.insertEdge(o),this.insertPoint(this.argIndex,i[0],L.BOUNDARY)},insertPoint:function(t,e,n){var i=this.nodes.addNode(e),r=i.getLabel();null===r?i.label=new gn(t,n):r.setLocation(t,n)},createEdgeSetIntersector:function(){return new Fn},addSelfIntersectionNodes:function(t){for(var e=this.edges.iterator();e.hasNext();)for(var n=e.next(),i=n.getLabel().getLocation(t),r=n.eiList.iterator();r.hasNext();){var s=r.next();this.addSelfIntersectionNode(t,s.coord,i)}},add:function(){if(1!==arguments.length)return Cn.prototype.add.apply(this,arguments);var t=arguments[0];if(t.isEmpty())return null;if(t instanceof Ot&&(this.useBoundaryDeterminationRule=!1),t instanceof Tt)this.addPolygon(t);else if(t instanceof St)this.addLineString(t);else if(t instanceof Lt)this.addPoint(t);else if(t instanceof Pt)this.addCollection(t);else if(t instanceof gt)this.addCollection(t);else if(t instanceof Ot)this.addCollection(t);else{if(!(t instanceof ft))throw new UnsupportedOperationException(t.getClass().getName());this.addCollection(t)}},addCollection:function(t){for(var e=0;e50?(null===this.areaPtLocator&&(this.areaPtLocator=new Un(this.parentGeom)),this.areaPtLocator.locate(t)):this.ptLocator.locate(t,this.parentGeom)},findEdge:function(){if(1===arguments.length){var t=arguments[0];return this.lineEdgeMap.get(t)}return Cn.prototype.findEdge.apply(this,arguments)},interfaces_:function(){return[]},getClass:function(){return $n}}),$n.determineBoundary=function(t,e){return t.isInBoundary(e)?L.BOUNDARY:L.INTERIOR},e(ti.prototype,{getArgGeometry:function(t){return this.arg[t].getGeometry()},setComputationPrecision:function(t){this.resultPrecisionModel=t,this.li.setPrecisionModel(this.resultPrecisionModel)},interfaces_:function(){return[]},getClass:function(){return ti}}),e(ei.prototype,{compareTo:function(t){var e=t,n=ei.compareOriented(this.pts,this._orientation,e.pts,e._orientation);return n},interfaces_:function(){return[s]},getClass:function(){return ei}}),ei.orientation=function(t){return 1===H.increasingDirection(t)},ei.compareOriented=function(t,e,n,i){for(var r=e?1:-1,s=i?1:-1,o=e?t.length:-1,a=i?n.length:-1,u=e?0:t.length-1,l=i?0:n.length-1;;){var h=t[u].compareTo(n[l]);if(0!==h)return h;u+=r,l+=s;var c=u===o,f=l===a;if(c&&!f)return-1;if(!c&&f)return 1;if(c&&f)return 0}},e(ni.prototype,{print:function(t){t.print("MULTILINESTRING ( ");for(var e=0;e0&&t.print(","),t.print("(");for(var i=n.getCoordinates(),r=0;r0&&t.print(","),t.print(i[r].x+" "+i[r].y);t.println(")")}t.print(") ")},addAll:function(t){for(var e=t.iterator();e.hasNext();)this.add(e.next())},findEdgeIndex:function(t){for(var e=0;er;r++)n.isNull(r)||!n.isArea()||i.isNull(r)||(0===i.getDelta(r)?n.toLine(r):(f.isTrue(!i.isNull(r,cn.LEFT),"depth of LEFT side has not been initialized"),n.setLocation(r,cn.LEFT,i.getLocation(r,cn.LEFT)),f.isTrue(!i.isNull(r,cn.RIGHT),"depth of RIGHT side has not been initialized"),n.setLocation(r,cn.RIGHT,i.getLocation(r,cn.RIGHT))))}}},computeLabelling:function(){for(var t=this.graph.getNodes().iterator();t.hasNext();){var e=t.next();e.getEdges().computeLabelling(this.arg)}this.mergeSymLabels(),this.updateNodeLabelling()},labelIncompleteNodes:function(){for(var t=0,e=this.graph.getNodes().iterator();e.hasNext();){var n=e.next(),i=n.getLabel();n.isIsolated()&&(t++,i.isNull(0)?this.labelIncompleteNode(n,0):this.labelIncompleteNode(n,1)),n.getEdges().updateLabelling(i)}},isCoveredByA:function(t){return!!this.isCovered(t,this.resultPolyList)},interfaces_:function(){return[]},getClass:function(){return ii}}),ii.overlayOp=function(t,e,n){var i=new ii(t,e),r=i.getResultGeometry(n);return r},ii.intersection=function(t,e){if(t.isEmpty()||e.isEmpty())return ii.createEmptyResult(ii.INTERSECTION,t,e,t.getFactory());if(t.isGeometryCollection()){var n=e;return hn.map(t,{interfaces_:function(){return[MapOp]},map:function(t){return t.intersection(n)}})}return t.checkNotGeometryCollection(t),t.checkNotGeometryCollection(e),si.overlayOp(t,e,ii.INTERSECTION)},ii.symDifference=function(t,e){if(t.isEmpty()||e.isEmpty()){if(t.isEmpty()&&e.isEmpty())return ii.createEmptyResult(ii.SYMDIFFERENCE,t,e,t.getFactory());if(t.isEmpty())return e.copy();if(e.isEmpty())return t.copy()}return t.checkNotGeometryCollection(t),t.checkNotGeometryCollection(e),si.overlayOp(t,e,ii.SYMDIFFERENCE)},ii.resultDimension=function(t,e,n){var i=e.getDimension(),r=n.getDimension(),s=-1;switch(t){case ii.INTERSECTION:s=Math.min(i,r);break;case ii.UNION:s=Math.max(i,r);break;case ii.DIFFERENCE:s=i;break;case ii.SYMDIFFERENCE:s=Math.max(i,r)}return s},ii.createEmptyResult=function(t,e,n,i){var r=null;switch(ii.resultDimension(t,e,n)){case-1:r=i.createGeometryCollection(new Array(0).fill(null));break;case 0:r=i.createPoint();break;case 1:r=i.createLineString();break;case 2:r=i.createPolygon()}return r},ii.difference=function(t,e){return t.isEmpty()?ii.createEmptyResult(ii.DIFFERENCE,t,e,t.getFactory()):e.isEmpty()?t.copy():(t.checkNotGeometryCollection(t),t.checkNotGeometryCollection(e),si.overlayOp(t,e,ii.DIFFERENCE))},ii.isResultOfOp=function(){if(2===arguments.length){var t=arguments[0],e=arguments[1],n=t.getLocation(0),i=t.getLocation(1);return ii.isResultOfOp(n,i,e)}if(3===arguments.length){var r=arguments[0],s=arguments[1],o=arguments[2];switch(r===L.BOUNDARY&&(r=L.INTERIOR),s===L.BOUNDARY&&(s=L.INTERIOR),o){case ii.INTERSECTION:return r===L.INTERIOR&&s===L.INTERIOR;case ii.UNION:return r===L.INTERIOR||s===L.INTERIOR;case ii.DIFFERENCE:return r===L.INTERIOR&&s!==L.INTERIOR;case ii.SYMDIFFERENCE:return r===L.INTERIOR&&s!==L.INTERIOR||r!==L.INTERIOR&&s===L.INTERIOR}return!1}},ii.INTERSECTION=1,ii.UNION=2,ii.DIFFERENCE=3,ii.SYMDIFFERENCE=4,e(ri.prototype,{selfSnap:function(t){var e=new Ie(t),n=e.snapTo(t,this.snapTolerance);return n},removeCommonBits:function(t){this.cbr=new Se,this.cbr.add(t[0]),this.cbr.add(t[1]);var e=new Array(2).fill(null);return e[0]=this.cbr.removeCommonBits(t[0].copy()),e[1]=this.cbr.removeCommonBits(t[1].copy()),e},prepareResult:function(t){return this.cbr.addCommonBits(t),t},getResultGeometry:function(t){var e=this.snap(this.geom),n=ii.overlayOp(e[0],e[1],t);return this.prepareResult(n)},checkValid:function(t){t.isValid()||A.out.println("Snapped geometry is invalid")},computeSnapTolerance:function(){this.snapTolerance=Ie.computeOverlaySnapTolerance(this.geom[0],this.geom[1])},snap:function(t){var e=this.removeCommonBits(t),n=Ie.snap(e[0],e[1],this.snapTolerance);return n},interfaces_:function(){return[]},getClass:function(){return ri}}),ri.overlayOp=function(t,e,n){var i=new ri(t,e);return i.getResultGeometry(n)},ri.union=function(t,e){return ri.overlayOp(t,e,ii.UNION)},ri.intersection=function(t,e){return ri.overlayOp(t,e,ii.INTERSECTION)},ri.symDifference=function(t,e){return ri.overlayOp(t,e,ii.SYMDIFFERENCE)},ri.difference=function(t,e){return ri.overlayOp(t,e,ii.DIFFERENCE)},e(si.prototype,{getResultGeometry:function(t){var e=null,n=!1,i=null;try{e=ii.overlayOp(this.geom[0],this.geom[1],t);var r=!0;r&&(n=!0)}catch(s){if(!(s instanceof l))throw s;i=s}finally{}if(!n)try{e=ri.overlayOp(this.geom[0],this.geom[1],t)}catch(s){throw s instanceof l?i:s}finally{}return e},interfaces_:function(){return[]},getClass:function(){return si}}),si.overlayOp=function(t,e,n){var i=new si(t,e);return i.getResultGeometry(n)},si.union=function(t,e){return si.overlayOp(t,e,ii.UNION)},si.intersection=function(t,e){return si.overlayOp(t,e,ii.INTERSECTION)},si.symDifference=function(t,e){return si.overlayOp(t,e,ii.SYMDIFFERENCE)},si.difference=function(t,e){return si.overlayOp(t,e,ii.DIFFERENCE)},e(oi.prototype,{addPolygon:function(t){if(t.isEmpty())return null;var e=null,n=0,i=this.horizontalBisector(t);if(0===i.getLength())n=0,e=i.getCoordinate();else{var r=si.overlayOp(i,t,ii.INTERSECTION),s=this.widestGeometry(r);n=s.getEnvelopeInternal().getWidth(),e=oi.centre(s.getEnvelopeInternal())}(null===this.interiorPoint||n>this.maxWidth)&&(this.interiorPoint=e,this.maxWidth=n)},getInteriorPoint:function(){return this.interiorPoint},widestGeometry:function zo(){if(arguments[0]instanceof ft){var t=arguments[0];if(t.isEmpty())return t;for(var zo=t.getGeometryN(0),e=1;ezo.getEnvelopeInternal().getWidth()&&(zo=t.getGeometryN(e));return zo}if(arguments[0]instanceof B){var n=arguments[0];return n instanceof ft?this.widestGeometry(n):n}},horizontalBisector:function(t){var e=t.getEnvelopeInternal(),n=ai.getBisectorY(t);return this.factory.createLineString([new g(e.getMinX(),n),new g(e.getMaxX(),n)])},add:function(t){if(t instanceof Tt)this.addPolygon(t);else if(t instanceof ft)for(var e=t,n=0;nthis.loY&&(this.loY=t):t>this.centreY&&tt;t++)if(null!==this.subnode[t])return!0;return!1},isPrunable:function(){return!(this.hasChildren()||this.hasItems())},addAllItems:function(t){t.addAll(this.items);for(var e=0;2>e;e++)null!==this.subnode[e]&&this.subnode[e].addAllItems(t);return t},size:function(){for(var t=0,e=0;2>e;e++)null!==this.subnode[e]&&(t+=this.subnode[e].size());return t+this.items.size()},addAllItemsFromOverlapping:function(t,e){return null===t||this.isSearchMatch(t)?(e.addAll(this.items),null!==this.subnode[0]&&this.subnode[0].addAllItemsFromOverlapping(t,e),void(null!==this.subnode[1]&&this.subnode[1].addAllItemsFromOverlapping(t,e))):null},hasItems:function(){return!this.items.isEmpty()},remove:function(t,e){if(!this.isSearchMatch(t))return!1;for(var n=!1,i=0;2>i;i++)if(null!==this.subnode[i]&&(n=this.subnode[i].remove(t,e))){this.subnode[i].isPrunable()&&(this.subnode[i]=null);break}return n?n:n=this.items.remove(e)},getItems:function(){return this.items},depth:function(){for(var t=0,e=0;2>e;e++)if(null!==this.subnode[e]){var n=this.subnode[e].depth();n>t&&(t=n)}return t+1},nodeSize:function(){for(var t=0,e=0;2>e;e++)null!==this.subnode[e]&&(t+=this.subnode[e].nodeSize());return t+1},add:function(t){this.items.add(t)},interfaces_:function(){return[]},getClass:function(){return ci}}),ci.getSubnodeIndex=function(t,e){var n=-1;return t.min>=e&&(n=1),t.max<=e&&(n=0),n},e(fi.prototype,{expandToInclude:function(t){t.max>this.max&&(this.max=t.max),t.minn||this.max=this.min&&e<=this.max}}else if(2===arguments.length){var n=arguments[0],i=arguments[1];return n>=this.min&&i<=this.max}},init:function(t,e){this.min=t,this.max=e,t>e&&(this.min=e,this.max=t)},getMax:function(){return this.max},interfaces_:function(){return[]},getClass:function(){return fi}}),gi.exponent=function(t){return di(64,t)-1023},gi.powerOf2=function(t){return Math.pow(2,t)},e(pi.prototype,{getInterval:function(){return this.interval},getLevel:function(){return this.level},computeKey:function(t){for(this.level=pi.computeLevel(t),this.interval=new fi,this.computeInterval(this.level,t);!this.interval.contains(t);)this.level+=1,this.computeInterval(this.level,t)},computeInterval:function(t,e){var n=gi.powerOf2(t);this.pt=Math.floor(e.getMin()/n)*n,this.interval.init(this.pt,this.pt+n)},getPoint:function(){return this.pt},interfaces_:function(){return[]},getClass:function(){return pi}}),pi.computeLevel=function(t){var e=t.getWidth(),n=gi.exponent(e)+1;return n},h(vi,ci),e(vi.prototype,{getInterval:function(){return this.interval},find:function(t){var e=ci.getSubnodeIndex(t,this.centre);if(-1===e)return this;if(null!==this.subnode[e]){var n=this.subnode[e];return n.find(t)}return this},insert:function(t){f.isTrue(null===this.interval||this.interval.contains(t.interval));var e=ci.getSubnodeIndex(t.interval,this.centre);if(t.level===this.level-1)this.subnode[e]=t;else{var n=this.createSubnode(e);n.insert(t),this.subnode[e]=n}},isSearchMatch:function(t){return t.overlaps(this.interval)},getSubnode:function(t){return null===this.subnode[t]&&(this.subnode[t]=this.createSubnode(t)),this.subnode[t]},getNode:function(t){var e=ci.getSubnodeIndex(t,this.centre);if(-1!==e){var n=this.getSubnode(e);return n.getNode(t)}return this},createSubnode:function(t){var e=0,n=0;switch(t){case 0:e=this.interval.getMin(),n=this.centre;break;case 1:e=this.centre,n=this.interval.getMax()}var i=new fi(e,n),r=new vi(i,this.level-1);return r},interfaces_:function(){return[]},getClass:function(){return vi}}),vi.createNode=function(t){var e=new pi(t),n=new vi(e.getInterval(),e.getLevel());return n},vi.createExpanded=function(t,e){var n=new fi(e);null!==t&&n.expandToInclude(t.interval);var i=vi.createNode(n);return null!==t&&i.insert(t),i},e(mi.prototype,{interfaces_:function(){return[]},getClass:function(){return mi}}),mi.isZeroWidth=function(t,e){var n=e-t;if(0===n)return!0;var i=Math.max(Math.abs(t),Math.abs(e)),r=n/i,s=gi.exponent(r);return s<=mi.MIN_BINARY_EXPONENT},mi.MIN_BINARY_EXPONENT=-50,h(yi,ci),e(yi.prototype,{insert:function(t,e){var n=ci.getSubnodeIndex(t,yi.origin);if(-1===n)return this.add(e),null;var i=this.subnode[n];if(null===i||!i.getInterval().contains(t)){var r=vi.createExpanded(i,t);this.subnode[n]=r}this.insertContained(this.subnode[n],t,e)},isSearchMatch:function(t){return!0},insertContained:function(t,e,n){f.isTrue(t.getInterval().contains(e));var i=mi.isZeroWidth(e.getMin(),e.getMax()),r=null;r=i?t.find(e):t.getNode(e),r.add(n)},interfaces_:function(){return[]},getClass:function(){return yi}}),yi.origin=0,e(xi.prototype,{size:function(){return null!==this.root?this.root.size():0},insert:function(t,e){this.collectStats(t);var n=xi.ensureExtent(t,this.minExtent);this.root.insert(n,e)},query:function(){if(1===arguments.length){if("number"==typeof arguments[0]){var t=arguments[0];return this.query(new fi(t,t))}if(arguments[0]instanceof fi){var e=arguments[0],n=new I;return this.query(e,n),n}}else if(2===arguments.length){var i=arguments[0],r=arguments[1];this.root.addAllItemsFromOverlapping(i,r)}},iterator:function(){var t=new I;return this.root.addAllItems(t),t.iterator()},remove:function(t,e){var n=xi.ensureExtent(t,this.minExtent);return this.root.remove(n,e)},collectStats:function(t){var e=t.getWidth();e0&&(this.minExtent=e)},depth:function(){return null!==this.root?this.root.depth():0},nodeSize:function(){return null!==this.root?this.root.nodeSize():0},interfaces_:function(){return[]},getClass:function(){return xi}}),xi.ensureExtent=function(t,e){var n=t.getMin(),i=t.getMax();return n!==i?t:(n===i&&(n-=e/2,i=n+e/2),new fi(n,i))},e(Ei.prototype,{isInside:function(t){},interfaces_:function(){return[]},getClass:function(){return Ei}}),e(Ii.prototype,{testLineSegment:function(t,e){var n=null,i=null,r=null,s=null,o=null,a=e.p0,u=e.p1;i=a.x-t.x,r=a.y-t.y,s=u.x-t.x,o=u.y-t.y,(r>0&&0>=o||o>0&&0>=r)&&(n=ue.signOfDet2x2(i,r,s,o)/(o-r),n>0&&this.crossings++)},buildIndex:function(){this.tree=new xi;for(var t=H.removeRepeatedPoints(this.ring.getCoordinates()),e=$e.getChains(t),n=0;nMath.PI;)t-=Ci.PI_TIMES_2;for(;t<=-Math.PI;)t+=Ci.PI_TIMES_2;return t},Ci.angle=function(){if(1===arguments.length){var t=arguments[0];return Math.atan2(t.y,t.x)}if(2===arguments.length){var e=arguments[0],n=arguments[1],i=n.x-e.x,r=n.y-e.y;return Math.atan2(r,i)}},Ci.isAcute=function(t,e,n){var i=t.x-e.x,r=t.y-e.y,s=n.x-e.x,o=n.y-e.y,a=i*s+r*o;return a>0},Ci.isObtuse=function(t,e,n){var i=t.x-e.x,r=t.y-e.y,s=n.x-e.x,o=n.y-e.y,a=i*s+r*o;return 0>a},Ci.interiorAngle=function(t,e,n){var i=Ci.angle(e,t),r=Ci.angle(e,n);return Math.abs(r-i)},Ci.normalizePositive=function(t){if(0>t){for(;0>t;)t+=Ci.PI_TIMES_2;t>=Ci.PI_TIMES_2&&(t=0)}else{for(;t>=Ci.PI_TIMES_2;)t-=Ci.PI_TIMES_2;0>t&&(t=0)}return t},Ci.angleBetween=function(t,e,n){var i=Ci.angle(e,t),r=Ci.angle(e,n);return Ci.diff(i,r)},Ci.diff=function(t,e){var n=null;return n=e>t?e-t:t-e,n>Math.PI&&(n=2*Math.PI-n),n},Ci.toRadians=function(t){return t*Math.PI/180},Ci.getTurn=function(t,e){var n=Math.sin(e-t);return n>0?Ci.COUNTERCLOCKWISE:0>n?Ci.CLOCKWISE:Ci.NONE},Ci.angleBetweenOriented=function(t,e,n){var i=Ci.angle(e,t),r=Ci.angle(e,n),s=r-i;return s<=-Math.PI?s+Ci.PI_TIMES_2:s>Math.PI?s-Ci.PI_TIMES_2:s},Ci.PI_TIMES_2=2*Math.PI,Ci.PI_OVER_2=Math.PI/2,Ci.PI_OVER_4=Math.PI/4,Ci.COUNTERCLOCKWISE=he.COUNTERCLOCKWISE,Ci.CLOCKWISE=he.CLOCKWISE,Ci.NONE=he.COLLINEAR,e(Si.prototype,{area:function(){return Si.area(this.p0,this.p1,this.p2)},signedArea:function(){return Si.signedArea(this.p0,this.p1,this.p2)},interpolateZ:function(t){if(null===t)throw new i("Supplied point is null.");return Si.interpolateZ(t,this.p0,this.p1,this.p2)},longestSideLength:function(){return Si.longestSideLength(this.p0,this.p1,this.p2)},isAcute:function(){return Si.isAcute(this.p0,this.p1,this.p2)},circumcentre:function(){return Si.circumcentre(this.p0,this.p1,this.p2)},area3D:function(){return Si.area3D(this.p0,this.p1,this.p2)},centroid:function(){return Si.centroid(this.p0,this.p1,this.p2)},inCentre:function(){return Si.inCentre(this.p0,this.p1,this.p2)},interfaces_:function(){return[]},getClass:function(){return Si}}),Si.area=function(t,e,n){return Math.abs(((n.x-t.x)*(e.y-t.y)-(e.x-t.x)*(n.y-t.y))/2)},Si.signedArea=function(t,e,n){return((n.x-t.x)*(e.y-t.y)-(e.x-t.x)*(n.y-t.y))/2},Si.det=function(t,e,n,i){return t*i-e*n},Si.interpolateZ=function(t,e,n,i){var r=e.x,s=e.y,o=n.x-r,a=i.x-r,u=n.y-s,l=i.y-s,h=o*l-a*u,c=t.x-r,f=t.y-s,g=(l*c-a*f)/h,d=(-u*c+o*f)/h,p=e.z+g*(n.z-e.z)+d*(i.z-e.z);return p},Si.longestSideLength=function(t,e,n){var i=t.distance(e),r=e.distance(n),s=n.distance(t),o=i;return r>o&&(o=r),s>o&&(o=s),o},Si.isAcute=function(t,e,n){return Ci.isAcute(t,e,n)&&Ci.isAcute(e,n,t)?!!Ci.isAcute(n,t,e):!1},Si.circumcentre=function(t,e,n){var i=n.x,r=n.y,s=t.x-i,o=t.y-r,a=e.x-i,u=e.y-r,l=2*Si.det(s,o,a,u),h=Si.det(o,s*s+o*o,u,a*a+u*u),c=Si.det(s,s*s+o*o,a,a*a+u*u),f=i-h/l,d=r+c/l;return new g(f,d)},Si.perpendicularBisector=function(t,e){var n=e.x-t.x,i=e.y-t.y,r=new F(t.x+n/2,t.y+i/2,1),s=new F(t.x-i+n/2,t.y+n+i/2,1);return new F(r,s)},Si.angleBisector=function(t,e,n){var i=e.distance(t),r=e.distance(n),s=i/(i+r),o=n.x-t.x,a=n.y-t.y,u=new g(t.x+s*o,t.y+s*a);return u},Si.area3D=function(t,e,n){var i=e.x-t.x,r=e.y-t.y,s=e.z-t.z,o=n.x-t.x,a=n.y-t.y,u=n.z-t.z,l=r*u-s*a,h=s*o-i*u,c=i*a-r*o,f=l*l+h*h+c*c,g=Math.sqrt(f)/2;return g},Si.centroid=function(t,e,n){var i=(t.x+e.x+n.x)/3,r=(t.y+e.y+n.y)/3;return new g(i,r)},Si.inCentre=function(t,e,n){var i=e.distance(n),r=t.distance(n),s=t.distance(e),o=i+r+s,a=(i*t.x+r*e.x+s*n.x)/o,u=(i*t.y+r*e.y+s*n.y)/o;return new g(a,u)},e(wi.prototype,{getRadius:function(){return this.compute(),this.radius},getDiameter:function(){switch(this.compute(),this.extremalPts.length){case 0:return this.input.getFactory().createLineString();case 1:return this.input.getFactory().createPoint(this.centre)}var t=this.extremalPts[0],e=this.extremalPts[1];return this.input.getFactory().createLineString([t,e])},getExtremalPoints:function(){return this.compute(),this.extremalPts},computeCirclePoints:function(){if(this.input.isEmpty())return this.extremalPts=new Array(0).fill(null),null;if(1===this.input.getNumPoints()){var t=this.input.getCoordinates();return this.extremalPts=[new g(t[0])],null}var e=this.input.convexHull(),n=e.getCoordinates(),t=n;if(n[0].equals2D(n[n.length-1])&&(t=new Array(n.length-1).fill(null),H.copyDeep(n,0,t,0,n.length-1)),t.length<=2)return this.extremalPts=H.copyDeep(t),null;for(var i=wi.lowestPoint(t),r=wi.pointWitMinAngleWithX(t,i),s=0;su&&(u=-u);var l=Math.sqrt(a*a+u*u),h=u/l;n>h&&(n=h,i=o)}}return i},wi.lowestPoint=function(t){for(var e=t[0],n=1;nu&&(i=u,s=a)}}return s},e(Li.prototype,{getWidthCoordinate:function(){return this.computeMinimumDiameter(),this.minWidthPt},getSupportingSegment:function(){return this.computeMinimumDiameter(),this.inputGeom.getFactory().createLineString([this.minBaseSeg.p0,this.minBaseSeg.p1])},getDiameter:function(){if(this.computeMinimumDiameter(),null===this.minWidthPt)return this.inputGeom.getFactory().createLineString(null);var t=this.minBaseSeg.project(this.minWidthPt);return this.inputGeom.getFactory().createLineString([t,this.minWidthPt])},computeWidthConvex:function(t){t instanceof Tt?this.convexHullPts=t.getExteriorRing().getCoordinates():this.convexHullPts=t.getCoordinates(),0===this.convexHullPts.length?(this.minWidth=0,this.minWidthPt=null,this.minBaseSeg=null):1===this.convexHullPts.length?(this.minWidth=0,this.minWidthPt=this.convexHullPts[0],this.minBaseSeg.p0=this.convexHullPts[0],this.minBaseSeg.p1=this.convexHullPts[0]):2===this.convexHullPts.length||3===this.convexHullPts.length?(this.minWidth=0,this.minWidthPt=this.convexHullPts[0],this.minBaseSeg.p0=this.convexHullPts[0],this.minBaseSeg.p1=this.convexHullPts[1]):this.computeConvexRingMinDiameter(this.convexHullPts)},computeConvexRingMinDiameter:function(t){this.minWidth=r.MAX_VALUE;for(var e=1,n=new ce,i=0;i=i;)i=r,s=o,o=Li.nextIndex(t,s),r=e.distancePerpendicular(t[o]);return ii&&(i=u),n>u&&(n=u);var l=Li.computeC(-e,t,this.convexHullPts[a]);l>o&&(o=l),s>l&&(s=l)}var h=Li.computeSegmentForLine(-t,-e,o),c=Li.computeSegmentForLine(-t,-e,s),f=Li.computeSegmentForLine(-e,t,i),g=Li.computeSegmentForLine(-e,t,n),d=f.lineIntersection(h),p=g.lineIntersection(h),v=g.lineIntersection(c),m=f.lineIntersection(c),y=this.inputGeom.getFactory().createLinearRing([d,p,v,m,d]);return this.inputGeom.getFactory().createPolygon(y,null)},interfaces_:function(){return[]},getClass:function(){return Li}}),Li.nextIndex=function(t,e){return e++,e>=t.length&&(e=0),e},Li.computeC=function(t,e,n){return t*n.y-e*n.x},Li.getMinimumDiameter=function(t){return new Li(t).getDiameter()},Li.getMinimumRectangle=function(t){return new Li(t).getMinimumRectangle()},Li.computeSegmentForLine=function(t,e,n){var i=null,r=null;return Math.abs(e)>Math.abs(t)?(i=new g(0,n/e),r=new g(1,n/e-t/e)):(i=new g(n/t,0),r=new g(n/t-e/t,1)),new ce(i,r)};var co=Object.freeze({Centroid:ge,CGAlgorithms:he,ConvexHull:me,InteriorPointArea:oi,InteriorPointLine:ui,InteriorPointPoint:li,RobustLineIntersector:ae,MCPointInRing:Ii,MinimumBoundingCircle:wi,MinimumDiameter:Li});e(Ri.prototype,{getResultGeometry:function(){return new Ti(this.distanceTolerance).transform(this.inputGeom)},setDistanceTolerance:function(t){if(0>=t)throw new i("Tolerance must be positive");this.distanceTolerance=t},interfaces_:function(){return[]},getClass:function(){return Ri}}),Ri.densifyPoints=function(t,e,n){for(var i=new ce,r=new N,s=0;s1)for(var u=o/a,l=1;a>l;l++){var h=l*u/o,c=i.pointAlong(h);n.makePrecise(c),r.add(c,!1)}}return r.add(t[t.length-1],!1),r.toCoordinateArray()},Ri.densify=function(t,e){var n=new Ri(t);return n.setDistanceTolerance(e),n.getResultGeometry()},h(Ti,xe),e(Ti.prototype,{transformMultiPolygon:function(t,e){var n=xe.prototype.transformMultiPolygon.call(this,t,e);return this.createValidArea(n)},transformPolygon:function(t,e){var n=xe.prototype.transformPolygon.call(this,t,e);return e instanceof Ot?n:this.createValidArea(n)},transformCoordinates:function(t,e){var n=t.toCoordinateArray(),i=Ri.densifyPoints(n,this.distanceTolerance,e.getPrecisionModel());return e instanceof St&&1===i.length&&(i=new Array(0).fill(null)),this.factory.getCoordinateSequenceFactory().create(i)},createValidArea:function(t){return t.buffer(0)},interfaces_:function(){return[]},getClass:function(){return Ti}}),Ri.DensifyTransformer=Ti;var fo=Object.freeze({Densifier:Ri});e(Pi.prototype,{find:function(t){var e=this;do{if(null===e)return null;if(e.dest().equals2D(t))return e;e=e.oNext()}while(e!==this);return null},dest:function(){return this._sym._orig},oNext:function(){return this._sym._next},insert:function(t){if(this.oNext()===this)return this.insertAfter(t),null;var e=this.compareTo(t),n=this;do{var i=n.oNext(),r=i.compareTo(t);if(r!==e||i===this)return n.insertAfter(t),null;n=i}while(n!==this);f.shouldNeverReachHere()},insertAfter:function(t){f.equals(this._orig,t.orig());var e=this.oNext();this._sym.setNext(t),t.sym().setNext(e)},degree:function Vo(){var Vo=0,t=this;do Vo++,t=t.oNext();while(t!==this);return Vo},equals:function(){if(2===arguments.length){var t=arguments[0],e=arguments[1];return this._orig.equals2D(t)&&this._sym._orig.equals(e)}},deltaY:function(){return this._sym._orig.y-this._orig.y},sym:function(){return this._sym},prev:function(){return this._sym.next()._sym},compareAngularDirection:function(t){var e=this.deltaX(),n=this.deltaY(),i=t.deltaX(),r=t.deltaY();if(e===i&&n===r)return 0;var s=Je.quadrant(e,n),o=Je.quadrant(i,r);return s>o?1:o>s?-1:he.computeOrientation(t._orig,t.dest(),this.dest())},prevNode:function(){for(var t=this;2===t.degree();)if(t=t.prev(),t===this)return null;return t},compareTo:function(t){var e=t,n=this.compareAngularDirection(e);return n},next:function(){return this._next},setSym:function(t){this._sym=t},orig:function(){return this._orig},toString:function(){return"HE("+this._orig.x+" "+this._orig.y+", "+this._sym._orig.x+" "+this._sym._orig.y+")"},setNext:function(t){this._next=t},init:function(t){this.setSym(t),t.setSym(this),this.setNext(t),t.setNext(this)},deltaX:function(){return this._sym._orig.x-this._orig.x},interfaces_:function(){return[]},getClass:function(){return Pi}}),Pi.init=function(t,e){if(null!==t._sym||null!==e._sym||null!==t._next||null!==e._next)throw new IllegalStateException("Edges are already initialized");return t.init(e),t},Pi.create=function(t,e){var n=new Pi(t),i=new Pi(e);return n.init(i),n},h(bi,Pi),e(bi.prototype,{mark:function(){this._isMarked=!0},setMark:function(t){this._isMarked=t},isMarked:function(){return this._isMarked},interfaces_:function(){return[]},getClass:function(){return bi}}),bi.setMarkBoth=function(t,e){t.setMark(e),t.sym().setMark(e)},bi.isMarked=function(t){return t.isMarked()},bi.setMark=function(t,e){t.setMark(e)},bi.markBoth=function(t){t.mark(),t.sym().mark()},bi.mark=function(t){t.mark()},e(Oi.prototype,{insert:function(t,e,n){var i=this.create(t,e);null!==n?n.insert(i):this.vertexMap.put(t,i);var r=this.vertexMap.get(e);return null!==r?r.insert(i.sym()):this.vertexMap.put(e,i.sym()),i},create:function(t,e){var n=this.createEdge(t),i=this.createEdge(e);return Pi.init(n,i),n},createEdge:function(t){return new Pi(t)},addEdge:function(t,e){if(!Oi.isValidEdge(t,e))return null;var n=this.vertexMap.get(t),i=null;if(null!==n&&(i=n.find(e)),null!==i)return i;var r=this.insert(t,e,n);return r},getVertexEdges:function(){return this.vertexMap.values()},findEdge:function(t,e){var n=this.vertexMap.get(t);return null===n?null:n.find(e)},interfaces_:function(){return[]},getClass:function(){return Oi}}),Oi.isValidEdge=function(t,e){var n=e.compareTo(t);return 0!==n},h(_i,bi),e(_i.prototype,{setStart:function(){this._isStart=!0; +},isStart:function(){return this._isStart},interfaces_:function(){return[]},getClass:function(){return _i}}),h(Mi,Oi),e(Mi.prototype,{createEdge:function(t){return new _i(t)},interfaces_:function(){return[]},getClass:function(){return Mi}}),e(Di.prototype,{addLine:function(t){this.lines.add(this.factory.createLineString(t.toCoordinateArray()))},updateRingStartEdge:function(t){return t.isStart()||(t=t.sym(),t.isStart())?null===this.ringStartEdge?(this.ringStartEdge=t,null):void(t.orig().compareTo(this.ringStartEdge.orig())<0&&(this.ringStartEdge=t)):null},getResult:function(){return null===this.result&&this.computeResult(),this.result},process:function(t){var e=t.prevNode();null===e&&(e=t),this.stackEdges(e),this.buildLines()},buildRing:function(t){var e=new N,n=t;for(e.add(n.orig().copy(),!1);2===n.sym().degree();){var i=n.next();if(i===t)break;e.add(i.orig().copy(),!1),n=i}e.add(n.dest().copy(),!1),this.addLine(e)},buildLine:function(t){var e=new N,n=t;for(this.ringStartEdge=null,bi.markBoth(n),e.add(n.orig().copy(),!1);2===n.sym().degree();){this.updateRingStartEdge(n);var i=n.next();if(i===t)return this.buildRing(this.ringStartEdge),null;e.add(i.orig().copy(),!1),n=i,bi.markBoth(n)}e.add(n.dest().copy(),!1),this.stackEdges(n.sym()),this.addLine(e)},stackEdges:function(t){var e=t;do bi.isMarked(e)||this.nodeEdgeStack.add(e),e=e.oNext();while(e!==t)},computeResult:function(){for(var t=this.graph.getVertexEdges(),e=t.iterator();e.hasNext();){var n=e.next();bi.isMarked(n)||this.process(n)}this.result=this.factory.buildGeometry(this.lines)},buildLines:function(){for(;!this.nodeEdgeStack.empty();){var t=this.nodeEdgeStack.pop();bi.isMarked(t)||this.buildLine(t)}},add:function(){if(arguments[0]instanceof B){var t=arguments[0];t.apply({interfaces_:function(){return[q]},filter:function(t){t instanceof St&&this.add(t)}})}else if(R(arguments[0],v))for(var e=arguments[0],n=e.iterator();n.hasNext();){var i=n.next();this.add(i)}else if(arguments[0]instanceof St){var r=arguments[0];null===this.factory&&(this.factory=r.getFactory());for(var s=r.getCoordinateSequence(),o=!1,n=1;nt;t++)if(null!==this.subnode[t])return!0;return!1},isPrunable:function(){return!(this.hasChildren()||this.hasItems())},addAllItems:function(t){t.addAll(this.items);for(var e=0;4>e;e++)null!==this.subnode[e]&&this.subnode[e].addAllItems(t);return t},getNodeCount:function(){for(var t=0,e=0;4>e;e++)null!==this.subnode[e]&&(t+=this.subnode[e].size());return t+1},size:function(){for(var t=0,e=0;4>e;e++)null!==this.subnode[e]&&(t+=this.subnode[e].size());return t+this.items.size()},addAllItemsFromOverlapping:function(t,e){if(!this.isSearchMatch(t))return null;e.addAll(this.items);for(var n=0;4>n;n++)null!==this.subnode[n]&&this.subnode[n].addAllItemsFromOverlapping(t,e)},visitItems:function(t,e){for(var n=this.items.iterator();n.hasNext();)e.visitItem(n.next())},hasItems:function(){return!this.items.isEmpty()},remove:function(t,e){if(!this.isSearchMatch(t))return!1;for(var n=!1,i=0;4>i;i++)if(null!==this.subnode[i]&&(n=this.subnode[i].remove(t,e))){this.subnode[i].isPrunable()&&(this.subnode[i]=null);break}return n?n:n=this.items.remove(e)},visit:function(t,e){if(!this.isSearchMatch(t))return null;this.visitItems(t,e);for(var n=0;4>n;n++)null!==this.subnode[n]&&this.subnode[n].visit(t,e)},getItems:function(){return this.items},depth:function(){for(var t=0,e=0;4>e;e++)if(null!==this.subnode[e]){var n=this.subnode[e].depth();n>t&&(t=n)}return t+1},isEmpty:function ko(){var ko=!0;this.items.isEmpty()||(ko=!1);for(var t=0;4>t;t++)null!==this.subnode[t]&&(this.subnode[t].isEmpty()||(ko=!1));return ko},add:function(t){this.items.add(t)},interfaces_:function(){return[u]},getClass:function(){return Ai}}),Ai.getSubnodeIndex=function(t,e,n){var i=-1;return t.getMinX()>=e&&(t.getMinY()>=n&&(i=3),t.getMaxY()<=n&&(i=1)),t.getMaxX()<=e&&(t.getMinY()>=n&&(i=2),t.getMaxY()<=n&&(i=0)),i},e(Fi.prototype,{getLevel:function(){return this.level},computeKey:function(){if(1===arguments.length){var t=arguments[0];for(this.level=Fi.computeQuadLevel(t),this.env=new C,this.computeKey(this.level,t);!this.env.contains(t);)this.level+=1,this.computeKey(this.level,t)}else if(2===arguments.length){var e=arguments[0],n=arguments[1],i=gi.powerOf2(e);this.pt.x=Math.floor(n.getMinX()/i)*i,this.pt.y=Math.floor(n.getMinY()/i)*i,this.env.init(this.pt.x,this.pt.x+i,this.pt.y,this.pt.y+i)}},getEnvelope:function(){return this.env},getCentre:function(){return new g((this.env.getMinX()+this.env.getMaxX())/2,(this.env.getMinY()+this.env.getMaxY())/2)},getPoint:function(){return this.pt},interfaces_:function(){return[]},getClass:function(){return Fi}}),Fi.computeQuadLevel=function(t){var e=t.getWidth(),n=t.getHeight(),i=e>n?e:n,r=gi.exponent(i)+1;return r},h(Gi,Ai),e(Gi.prototype,{find:function(t){var e=Ai.getSubnodeIndex(t,this.centrex,this.centrey);if(-1===e)return this;if(null!==this.subnode[e]){var n=this.subnode[e];return n.find(t)}return this},isSearchMatch:function(t){return this.env.intersects(t)},getSubnode:function(t){return null===this.subnode[t]&&(this.subnode[t]=this.createSubnode(t)),this.subnode[t]},getEnvelope:function(){return this.env},getNode:function(t){var e=Ai.getSubnodeIndex(t,this.centrex,this.centrey);if(-1!==e){var n=this.getSubnode(e);return n.getNode(t)}return this},createSubnode:function(t){var e=0,n=0,i=0,r=0;switch(t){case 0:e=this.env.getMinX(),n=this.centrex,i=this.env.getMinY(),r=this.centrey;break;case 1:e=this.centrex,n=this.env.getMaxX(),i=this.env.getMinY(),r=this.centrey;break;case 2:e=this.env.getMinX(),n=this.centrex,i=this.centrey,r=this.env.getMaxY();break;case 3:e=this.centrex,n=this.env.getMaxX(),i=this.centrey,r=this.env.getMaxY()}var s=new C(e,n,i,r),o=new Gi(s,this.level-1);return o},insertNode:function(t){f.isTrue(null===this.env||this.env.contains(t.env));var e=Ai.getSubnodeIndex(t.env,this.centrex,this.centrey);if(t.level===this.level-1)this.subnode[e]=t;else{var n=this.createSubnode(e);n.insertNode(t),this.subnode[e]=n}},interfaces_:function(){return[]},getClass:function(){return Gi}}),Gi.createNode=function(t){var e=new Fi(t),n=new Gi(e.getEnvelope(),e.getLevel());return n},Gi.createExpanded=function(t,e){var n=new C(e);null!==t&&n.expandToInclude(t.env);var i=Gi.createNode(n);return null!==t&&i.insertNode(t),i},h(qi,Ai),e(qi.prototype,{insert:function(t,e){var n=Ai.getSubnodeIndex(t,qi.origin.x,qi.origin.y);if(-1===n)return this.add(e),null;var i=this.subnode[n];if(null===i||!i.getEnvelope().contains(t)){var r=Gi.createExpanded(i,t);this.subnode[n]=r}this.insertContained(this.subnode[n],t,e)},isSearchMatch:function(t){return!0},insertContained:function(t,e,n){f.isTrue(t.getEnvelope().contains(e));var i=mi.isZeroWidth(e.getMinX(),e.getMaxX()),r=mi.isZeroWidth(e.getMinY(),e.getMaxY()),s=null;s=i||r?t.find(e):t.getNode(e),s.add(n)},interfaces_:function(){return[]},getClass:function(){return qi}}),qi.origin=new g(0,0),e(Bi.prototype,{size:function(){return null!==this.root?this.root.size():0},insert:function(t,e){this.collectStats(t);var n=Bi.ensureExtent(t,this.minExtent);this.root.insert(n,e)},query:function(){if(1===arguments.length){var t=arguments[0],e=new Yn;return this.query(t,e),e.getItems()}if(2===arguments.length){var n=arguments[0],i=arguments[1];this.root.visit(n,i)}},queryAll:function(){var t=new I;return this.root.addAllItems(t),t},remove:function(t,e){var n=Bi.ensureExtent(t,this.minExtent);return this.root.remove(n,e)},collectStats:function(t){var e=t.getWidth();e0&&(this.minExtent=e);var n=t.getHeight();n0&&(this.minExtent=n)},depth:function(){return null!==this.root?this.root.depth():0},isEmpty:function(){return null===this.root},interfaces_:function(){return[Fe,u]},getClass:function(){return Bi}}),Bi.ensureExtent=function(t,e){var n=t.getMinX(),i=t.getMaxX(),r=t.getMinY(),s=t.getMaxY();return n!==i&&r!==s?t:(n===i&&(n-=e/2,i=n+e/2),r===s&&(r-=e/2,s=r+e/2),new C(n,i,r,s))},Bi.serialVersionUID=-0x678b60c967a25400;var vo=Object.freeze({Quadtree:Bi}),mo=Object.freeze({STRtree:ke}),yo=Object.freeze({quadtree:vo,strtree:mo}),xo=["Point","MultiPoint","LineString","MultiLineString","Polygon","MultiPolygon"];e(zi.prototype,{read:function(t){var e=void 0;e="string"==typeof t?JSON.parse(t):t;var n=e.type;if(!Eo[n])throw new Error("Unknown GeoJSON type: "+e.type);return-1!==xo.indexOf(n)?Eo[n].apply(this,[e.coordinates]):"GeometryCollection"===n?Eo[n].apply(this,[e.geometries]):Eo[n].apply(this,[e])},write:function(t){var e=t.getGeometryType();if(!Io[e])throw new Error("Geometry is not supported");return Io[e].apply(this,[t])}});var Eo={Feature:function(t){var e={};for(var n in t)e[n]=t[n];if(t.geometry){var i=t.geometry.type;if(!Eo[i])throw new Error("Unknown GeoJSON type: "+t.type);e.geometry=this.read(t.geometry)}return t.bbox&&(e.bbox=Eo.bbox.apply(this,[t.bbox])),e},FeatureCollection:function(t){var e={};if(t.features){e.features=[];for(var n=0;ne;e++)this.precisionModel.makePrecise(t.points[e]);else if(t.geometries)for(e=0,n=t.geometries.length;n>e;e++)this.reducePrecision(t.geometries[e])}}),e(ki.prototype,{write:function(t){return this.parser.write(t)}}),e(Yi.prototype,{read:function(t){var e=this.parser.read(t);return this.precisionModel.getType()===ee.FIXED&&this.reducePrecision(e),e},reducePrecision:function(t){if(t.coordinate)this.precisionModel.makePrecise(t.coordinate);else if(t.points)for(var e=0,n=t.points.coordinates.length;n>e;e++)this.precisionModel.makePrecise(t.points.coordinates[e]);else if(t.geometries)for(var i=0,r=t.geometries.length;r>i;i++)this.reducePrecision(t.geometries[i])}}),e(Xi.prototype,{read:function(t){return t instanceof ol.geom.Point?this.convertFromPoint(t):t instanceof ol.geom.LineString?this.convertFromLineString(t):t instanceof ol.geom.LinearRing?this.convertFromLinearRing(t):t instanceof ol.geom.Polygon?this.convertFromPolygon(t):t instanceof ol.geom.MultiPoint?this.convertFromMultiPoint(t):t instanceof ol.geom.MultiLineString?this.convertFromMultiLineString(t):t instanceof ol.geom.MultiPolygon?this.convertFromMultiPolygon(t):t instanceof ol.geom.GeometryCollection?this.convertFromCollection(t):void 0},convertFromPoint:function(t){var e=t.getCoordinates();return this.geometryFactory.createPoint(new g(e[0],e[1]))},convertFromLineString:function(t){return this.geometryFactory.createLineString(t.getCoordinates().map(function(t){return new g(t[0],t[1])}))},convertFromLinearRing:function(t){return this.geometryFactory.createLinearRing(t.getCoordinates().map(function(t){return new g(t[0],t[1])}))},convertFromPolygon:function(t){for(var e=t.getLinearRings(),n=null,i=[],r=0;r=t&&(this.quadrantSegments=1),this.joinStyle!==Ki.JOIN_ROUND&&(this.quadrantSegments=Ki.DEFAULT_QUADRANT_SEGMENTS)},getJoinStyle:function(){return this.joinStyle},setJoinStyle:function(t){this.joinStyle=t},setSimplifyFactor:function(t){this.simplifyFactor=0>t?0:t},getSimplifyFactor:function(){return this.simplifyFactor},getQuadrantSegments:function(){return this.quadrantSegments},setEndCapStyle:function(t){this.endCapStyle=t},getMitreLimit:function(){return this.mitreLimit},setMitreLimit:function(t){this.mitreLimit=t},setSingleSided:function(t){this._isSingleSided=t},interfaces_:function(){return[]},getClass:function(){return Ki}}),Ki.bufferDistanceError=function(t){var e=Math.PI/2/t;return 1-Math.cos(e/2)},Ki.CAP_ROUND=1,Ki.CAP_FLAT=2,Ki.CAP_SQUARE=3,Ki.JOIN_ROUND=1,Ki.JOIN_MITRE=2,Ki.JOIN_BEVEL=3,Ki.DEFAULT_QUADRANT_SEGMENTS=8,Ki.DEFAULT_MITRE_LIMIT=5,Ki.DEFAULT_SIMPLIFY_FACTOR=.01,e(Zi.prototype,{getCoordinate:function(){return this.minCoord},getRightmostSide:function(t,e){var n=this.getRightmostSideOfSegment(t,e);return 0>n&&(n=this.getRightmostSideOfSegment(t,e-1)),0>n&&(this.minCoord=null,this.checkForRightmostCoordinate(t)),n},findRightmostEdgeAtVertex:function(){var t=this.minDe.getEdge().getCoordinates();f.isTrue(this.minIndex>0&&this.minIndexthis.minCoord.y&&n.y>this.minCoord.y&&i===he.CLOCKWISE&&(r=!0),r&&(this.minIndex=this.minIndex-1)},getRightmostSideOfSegment:function(t,e){var n=t.getEdge(),i=n.getCoordinates();if(0>e||e+1>=i.length)return-1;if(i[e].y===i[e+1].y)return-1;var r=cn.LEFT;return i[e].ythis.minCoord.x)&&(this.minDe=t,this.minIndex=n,this.minCoord=e[n])},findRightmostEdgeAtNode:function(){var t=this.minDe.getNode(),e=t.getEdges();this.minDe=e.getRightmostEdge(),this.minDe.isForward()||(this.minDe=this.minDe.getSym(),this.minIndex=this.minDe.getEdge().getCoordinates().length-1)},findEdge:function(t){for(var e=t.iterator();e.hasNext();){var n=e.next();n.isForward()&&this.checkForRightmostCoordinate(n)}f.isTrue(0!==this.minIndex||this.minCoord.equals(this.minDe.getCoordinate()),"inconsistency in rightmost processing"),0===this.minIndex?this.findRightmostEdgeAtNode():this.findRightmostEdgeAtVertex(),this.orientedDe=this.minDe;var i=this.getRightmostSide(this.minDe,this.minIndex);i===cn.LEFT&&(this.orientedDe=this.minDe.getSym())},interfaces_:function(){return[]},getClass:function(){return Zi}}),Qi.prototype.addLast=function(t){this.array_.push(t)},Qi.prototype.removeFirst=function(){return this.array_.shift()},Qi.prototype.isEmpty=function(){return 0===this.array_.length},e(Ji.prototype,{clearVisitedEdges:function(){for(var t=this.dirEdgeList.iterator();t.hasNext();){var e=t.next();e.setVisited(!1)}},getRightmostCoordinate:function(){return this.rightMostCoord},computeNodeDepth:function(t){for(var e=null,n=t.getEdges().iterator();n.hasNext();){var i=n.next();if(i.isVisited()||i.getSym().isVisited()){e=i;break}}if(null===e)throw new sn("unable to find edge to compute depths at "+t.getCoordinate());t.getEdges().computeDepths(e);for(var n=t.getEdges().iterator();n.hasNext();){var i=n.next();i.setVisited(!0),this.copySymDepths(i)}},computeDepth:function(t){this.clearVisitedEdges();var e=this.finder.getEdge();e.getNode(),e.getLabel();e.setEdgeDepths(cn.RIGHT,t),this.copySymDepths(e),this.computeDepths(e)},create:function(t){this.addReachable(t),this.finder.findEdge(this.dirEdgeList),this.rightMostCoord=this.finder.getCoordinate()},findResultEdges:function(){for(var t=this.dirEdgeList.iterator();t.hasNext();){var e=t.next();e.getDepth(cn.RIGHT)>=1&&e.getDepth(cn.LEFT)<=0&&!e.isInteriorAreaEdge()&&e.setInResult(!0)}},computeDepths:function(t){var e=new J,n=new Qi,i=t.getNode();for(n.addLast(i),e.add(i),t.setVisited(!0);!n.isEmpty();){var r=n.removeFirst();e.add(r),this.computeNodeDepth(r);for(var s=r.getEdges().iterator();s.hasNext();){var o=s.next(),a=o.getSym();if(!a.isVisited()){var u=a.getNode();e.contains(u)||(n.addLast(u),e.add(u))}}}},compareTo:function(t){var e=t;return this.rightMostCoord.xe.rightMostCoord.x?1:0},getEnvelope:function(){if(null===this.env){for(var t=new C,e=this.dirEdgeList.iterator();e.hasNext();)for(var n=e.next(),i=n.getEdge().getCoordinates(),r=0;ro},isShallowSampled:function(t,e,n,i,r){var s=Math.trunc((i-n)/$i.NUM_PTS_TO_CHECK);0>=s&&(s=1);for(var o=n;i>o;o+=s)if(!this.isShallow(t,e,this.inputLine[o],r))return!1;return!0},isConcave:function Uo(t,e,n){var i=he.computeOrientation(t,e,n),Uo=i===this.angleOrientation;return Uo},simplify:function(t){this.distanceTol=Math.abs(t),0>t&&(this.angleOrientation=he.CLOCKWISE),this.isDeleted=new Array(this.inputLine.length).fill(null);var e=!1;do e=this.deleteShallowConcavities();while(e);return this.collapseLine()},findNextNonDeletedIndex:function(t){for(var e=t+1;er},collapseLine:function(){for(var t=new N,e=0;e=0;n--)this.addPt(t[n])},isRedundant:function(t){if(this.ptList.size()<1)return!1;var e=this.ptList.get(this.ptList.size()-1),n=t.distance(e);return n=2&&(n=this.ptList.get(this.ptList.size()-2)),t.equals(e)?null:void this.ptList.add(t)},setMinimumVertexDistance:function(t){this.minimimVertexDistance=t},interfaces_:function(){return[]},getClass:function(){return tr}}),tr.COORDINATE_ARRAY_TYPE=new Array(0).fill(null),e(er.prototype,{addNextSegment:function(t,e){if(this.s0=this.s1,this.s1=this.s2,this.s2=t,this.seg0.setCoordinates(this.s0,this.s1),this.computeOffsetSegment(this.seg0,this.side,this.distance,this.offset0),this.seg1.setCoordinates(this.s1,this.s2),this.computeOffsetSegment(this.seg1,this.side,this.distance,this.offset1),this.s1.equals(this.s2))return null;var n=he.computeOrientation(this.s0,this.s1,this.s2),i=n===he.CLOCKWISE&&this.side===cn.LEFT||n===he.COUNTERCLOCKWISE&&this.side===cn.RIGHT;0===n?this.addCollinear(e):i?this.addOutsideTurn(n,e):this.addInsideTurn(n,e)},addLineEndCap:function(t,e){var n=new ce(t,e),i=new ce;this.computeOffsetSegment(n,cn.LEFT,this.distance,i);var r=new ce;this.computeOffsetSegment(n,cn.RIGHT,this.distance,r);var s=e.x-t.x,o=e.y-t.y,a=Math.atan2(o,s);switch(this.bufParams.getEndCapStyle()){case Ki.CAP_ROUND:this.segList.addPt(i.p1),this.addFilletArc(e,a+Math.PI/2,a-Math.PI/2,he.CLOCKWISE,this.distance),this.segList.addPt(r.p1);break;case Ki.CAP_FLAT:this.segList.addPt(i.p1),this.segList.addPt(r.p1);break;case Ki.CAP_SQUARE:var u=new g;u.x=Math.abs(this.distance)*Math.cos(a),u.y=Math.abs(this.distance)*Math.sin(a);var l=new g(i.p1.x+u.x,i.p1.y+u.y),h=new g(r.p1.x+u.x,r.p1.y+u.y);this.segList.addPt(l),this.segList.addPt(h)}},getCoordinates:function(){var t=this.segList.getCoordinates();return t},addMitreJoin:function(t,e,n,i){var r=!0,s=null;try{s=F.intersection(e.p0,e.p1,n.p0,n.p1);var o=0>=i?1:s.distance(t)/Math.abs(i);o>this.bufParams.getMitreLimit()&&(r=!1)}catch(a){if(!(a instanceof w))throw a;s=new g(0,0),r=!1}finally{}r?this.segList.addPt(s):this.addLimitedMitreJoin(e,n,i,this.bufParams.getMitreLimit())},addFilletCorner:function(t,e,n,i,r){var s=e.x-t.x,o=e.y-t.y,a=Math.atan2(o,s),u=n.x-t.x,l=n.y-t.y,h=Math.atan2(l,u);i===he.CLOCKWISE?h>=a&&(a+=2*Math.PI):a>=h&&(a-=2*Math.PI),this.segList.addPt(e),this.addFilletArc(t,a,h,i,r),this.segList.addPt(n)},addOutsideTurn:function(t,e){return this.offset0.p1.distance(this.offset1.p0)a)return null;var u=null,l=null;u=0,l=o/a;for(var h=u,c=new g;o>h;){var f=e+s*h;c.x=t.x+r*Math.cos(f),c.y=t.y+r*Math.sin(f),this.segList.addPt(c),h+=l}},addInsideTurn:function(t,e){if(this.li.computeIntersection(this.offset0.p0,this.offset0.p1,this.offset1.p0,this.offset1.p1),this.li.hasIntersection())this.segList.addPt(this.li.getIntersection(0));else if(this._hasNarrowConcaveAngle=!0,this.offset0.p1.distance(this.offset1.p0)0){var n=new g((this.closingSegLengthFactor*this.offset0.p1.x+this.s1.x)/(this.closingSegLengthFactor+1),(this.closingSegLengthFactor*this.offset0.p1.y+this.s1.y)/(this.closingSegLengthFactor+1));this.segList.addPt(n);var i=new g((this.closingSegLengthFactor*this.offset1.p0.x+this.s1.x)/(this.closingSegLengthFactor+1),(this.closingSegLengthFactor*this.offset1.p0.y+this.s1.y)/(this.closingSegLengthFactor+1));this.segList.addPt(i)}else this.segList.addPt(this.s1);this.segList.addPt(this.offset1.p0)}},createCircle:function(t){var e=new g(t.x+this.distance,t.y);this.segList.addPt(e),this.addFilletArc(t,0,2*Math.PI,-1,this.distance),this.segList.closeRing()},addBevelJoin:function(t,e){this.segList.addPt(t.p1),this.segList.addPt(e.p0)},init:function(t){this.distance=t,this.maxCurveSegmentError=t*(1-Math.cos(this.filletAngleQuantum/2)),this.segList=new tr,this.segList.setPrecisionModel(this.precisionModel),this.segList.setMinimumVertexDistance(t*er.CURVE_VERTEX_SNAP_DISTANCE_FACTOR)},addCollinear:function(t){this.li.computeIntersection(this.s0,this.s1,this.s1,this.s2);var e=this.li.getIntersectionNum();e>=2&&(this.bufParams.getJoinStyle()===Ki.JOIN_BEVEL||this.bufParams.getJoinStyle()===Ki.JOIN_MITRE?(t&&this.segList.addPt(this.offset0.p1),this.segList.addPt(this.offset1.p0)):this.addFilletCorner(this.s1,this.offset0.p1,this.offset1.p0,he.CLOCKWISE,this.distance))},closeRing:function(){this.segList.closeRing()},hasNarrowConcaveAngle:function(){return this._hasNarrowConcaveAngle},interfaces_:function(){return[]},getClass:function(){return er}}),er.OFFSET_SEGMENT_SEPARATION_FACTOR=.001,er.INSIDE_TURN_VERTEX_SNAP_DISTANCE_FACTOR=.001,er.CURVE_VERTEX_SNAP_DISTANCE_FACTOR=1e-6,er.MAX_CLOSING_SEG_LEN_FACTOR=80,e(nr.prototype,{getOffsetCurve:function(t,e){if(this.distance=e,0===e)return null;var n=0>e,i=Math.abs(e),r=this.getSegGen(i);t.length<=1?this.computePointCurve(t[0],r):this.computeOffsetCurve(t,n,r);var s=r.getCoordinates();return n&&H.reverse(s),s},computeSingleSidedBufferCurve:function(t,e,n){var i=this.simplifyTolerance(this.distance);if(e){n.addSegments(t,!0);var r=$i.simplify(t,-i),s=r.length-1;n.initSideSegments(r[s],r[s-1],cn.LEFT),n.addFirstSegment();for(var o=s-2;o>=0;o--)n.addNextSegment(r[o],!0)}else{n.addSegments(t,!1);var a=$i.simplify(t,i),u=a.length-1;n.initSideSegments(a[0],a[1],cn.LEFT),n.addFirstSegment();for(var o=2;u>=o;o++)n.addNextSegment(a[o],!0)}n.addLastSegment(),n.closeRing()},computeRingBufferCurve:function(t,e,n){var i=this.simplifyTolerance(this.distance);e===cn.RIGHT&&(i=-i);var r=$i.simplify(t,i),s=r.length-1;n.initSideSegments(r[s-1],r[0],e);for(var o=1;s>=o;o++){var a=1!==o;n.addNextSegment(r[o],a)}n.closeRing()},computeLineBufferCurve:function(t,e){var n=this.simplifyTolerance(this.distance),i=$i.simplify(t,n),r=i.length-1;e.initSideSegments(i[0],i[1],cn.LEFT);for(var s=2;r>=s;s++)e.addNextSegment(i[s],!0);e.addLastSegment(),e.addLineEndCap(i[r-1],i[r]);var o=$i.simplify(t,-n),a=o.length-1;e.initSideSegments(o[a],o[a-1],cn.LEFT);for(var s=a-2;s>=0;s--)e.addNextSegment(o[s],!0);e.addLastSegment(),e.addLineEndCap(o[1],o[0]),e.closeRing()},computePointCurve:function(t,e){switch(this.bufParams.getEndCapStyle()){case Ki.CAP_ROUND:e.createCircle(t);break;case Ki.CAP_SQUARE:e.createSquare(t)}},getLineCurve:function(t,e){if(this.distance=e,0>e&&!this.bufParams.isSingleSided())return null;if(0===e)return null;var n=Math.abs(e),i=this.getSegGen(n);if(t.length<=1)this.computePointCurve(t[0],i);else if(this.bufParams.isSingleSided()){var r=0>e;this.computeSingleSidedBufferCurve(t,r,i)}else this.computeLineBufferCurve(t,i);var s=i.getCoordinates();return s},getBufferParameters:function(){return this.bufParams},simplifyTolerance:function(t){return t*this.bufParams.getSimplifyFactor()},getRingCurve:function(t,e,n){if(this.distance=n,t.length<=2)return this.getLineCurve(t,n);if(0===n)return nr.copyCoordinates(t);var i=this.getSegGen(n);return this.computeRingBufferCurve(t,e,i),i.getCoordinates()},computeOffsetCurve:function(t,e,n){var i=this.simplifyTolerance(this.distance);if(e){var r=$i.simplify(t,-i),s=r.length-1;n.initSideSegments(r[s],r[s-1],cn.LEFT),n.addFirstSegment();for(var o=s-2;o>=0;o--)n.addNextSegment(r[o],!0)}else{var a=$i.simplify(t,i),u=a.length-1;n.initSideSegments(a[0],a[1],cn.LEFT),n.addFirstSegment();for(var o=2;u>=o;o++)n.addNextSegment(a[o],!0)}n.addLastSegment()},getSegGen:function(t){return new er(this.precisionModel,this.bufParams,t)},interfaces_:function(){return[]},getClass:function(){return nr}}),nr.copyCoordinates=function(t){for(var e=new Array(t.length).fill(null),n=0;nr.getMaxY()||this.findStabbedSegments(t,i.getDirectedEdges(),e)}return e}if(3===arguments.length)if(R(arguments[2],y)&&arguments[0]instanceof g&&arguments[1]instanceof In)for(var s=arguments[0],o=arguments[1],a=arguments[2],u=o.getEdge().getCoordinates(),n=0;nthis.seg.p1.y&&this.seg.reverse();var l=Math.max(this.seg.p0.x,this.seg.p1.x);if(!(lthis.seg.p1.y||he.computeOrientation(this.seg.p0,this.seg.p1,s)===he.RIGHT)){var h=o.getDepth(cn.LEFT);this.seg.p0.equals(u[n])||(h=o.getDepth(cn.RIGHT));var c=new rr(this.seg,h);a.add(c)}}else if(R(arguments[2],y)&&arguments[0]instanceof g&&R(arguments[1],y))for(var f=arguments[0],d=arguments[1],p=arguments[2],n=d.iterator();n.hasNext();){var v=n.next();v.isForward()&&this.findStabbedSegments(f,v,p)}},getDepth:function(t){var e=this.findStabbedSegments(t);if(0===e.size())return 0;var n=ho.min(e);return n.leftDepth},interfaces_:function(){return[]},getClass:function(){return ir}}),e(rr.prototype,{compareTo:function(t){var e=t;if(this.upwardSeg.minX()>=e.upwardSeg.maxX())return 1;if(this.upwardSeg.maxX()<=e.upwardSeg.minX())return-1;var n=this.upwardSeg.orientationIndex(e.upwardSeg);return 0!==n?n:(n=-1*e.upwardSeg.orientationIndex(this.upwardSeg),0!==n?n:this.upwardSeg.compareTo(e.upwardSeg))},compareX:function(t,e){var n=t.p0.compareTo(e.p0);return 0!==n?n:t.p1.compareTo(e.p1)},toString:function(){return this.upwardSeg.toString()},interfaces_:function(){return[s]},getClass:function(){return rr}}),ir.DepthSegment=rr,e(sr.prototype,{addPoint:function(t){if(this.distance<=0)return null;var e=t.getCoordinates(),n=this.curveBuilder.getLineCurve(e,this.distance);this.addCurve(n,L.EXTERIOR,L.INTERIOR)},addPolygon:function(t){var e=this.distance,n=cn.LEFT;this.distance<0&&(e=-this.distance,n=cn.RIGHT);var i=t.getExteriorRing(),r=H.removeRepeatedPoints(i.getCoordinates());if(this.distance<0&&this.isErodedCompletely(i,this.distance))return null;if(this.distance<=0&&r.length<3)return null;this.addPolygonRing(r,e,n,L.EXTERIOR,L.INTERIOR);for(var s=0;s0&&this.isErodedCompletely(o,-this.distance)||this.addPolygonRing(a,e,cn.opposite(n),L.INTERIOR,L.EXTERIOR)}},isTriangleErodedCompletely:function(t,e){var n=new Si(t[0],t[1],t[2]),i=n.inCentre(),r=he.distancePointLine(i,n.p0,n.p1);return r=bt.MINIMUM_VALID_SIZE&&he.isCCW(t)&&(s=r,o=i,n=cn.opposite(n));var a=this.curveBuilder.getRingCurve(t,n,e);this.addCurve(a,s,o)},add:function(t){if(t.isEmpty())return null;if(t instanceof Tt)this.addPolygon(t);else if(t instanceof St)this.addLineString(t);else if(t instanceof Lt)this.addPoint(t);else if(t instanceof Pt)this.addCollection(t);else if(t instanceof gt)this.addCollection(t);else if(t instanceof Ot)this.addCollection(t);else{if(!(t instanceof ft))throw new UnsupportedOperationException(t.getClass().getName());this.addCollection(t)}},isErodedCompletely:function(t,e){var n=t.getCoordinates();if(n.length<4)return 0>e;if(4===n.length)return this.isTriangleErodedCompletely(n,e);var i=t.getEnvelopeInternal(),r=Math.min(i.getHeight(),i.getWidth());return 0>e&&2*Math.abs(e)>r},addCollection:function(t){for(var e=0;ei||this.maxys;if(o)return!1;var a=this.intersectsToleranceSquare(t,e);return f.isTrue(!(o&&a),"Found bad envelope test"),a},initCorners:function(t){var e=.5;this.minx=t.x-e,this.maxx=t.x+e,this.miny=t.y-e,this.maxy=t.y+e,this.corner[0]=new g(this.maxx,this.maxy),this.corner[1]=new g(this.minx,this.maxy),this.corner[2]=new g(this.minx,this.miny),this.corner[3]=new g(this.maxx,this.miny)},intersects:function(t,e){return 1===this.scaleFactor?this.intersectsScaled(t,e):(this.copyScaled(t,this.p0Scaled),this.copyScaled(e,this.p1Scaled),this.intersectsScaled(this.p0Scaled,this.p1Scaled))},scale:function(t){return Math.round(t*this.scaleFactor)},getCoordinate:function(){return this.originalPt},copyScaled:function(t,e){e.x=this.scale(t.x),e.y=this.scale(t.y)},getSafeEnvelope:function(){if(null===this.safeEnv){var t=lr.SAFE_ENV_EXPANSION_FACTOR/this.scaleFactor;this.safeEnv=new C(this.originalPt.x-t,this.originalPt.x+t,this.originalPt.y-t,this.originalPt.y+t)}return this.safeEnv},intersectsPixelClosure:function(t,e){return this.li.computeIntersection(t,e,this.corner[0],this.corner[1]),this.li.hasIntersection()?!0:(this.li.computeIntersection(t,e,this.corner[1],this.corner[2]),this.li.hasIntersection()?!0:(this.li.computeIntersection(t,e,this.corner[2],this.corner[3]),this.li.hasIntersection()?!0:(this.li.computeIntersection(t,e,this.corner[3],this.corner[0]),!!this.li.hasIntersection())))},intersectsToleranceSquare:function(t,e){var n=!1,i=!1;return this.li.computeIntersection(t,e,this.corner[0],this.corner[1]),this.li.isProper()?!0:(this.li.computeIntersection(t,e,this.corner[1],this.corner[2]),this.li.isProper()?!0:(this.li.hasIntersection()&&(n=!0),this.li.computeIntersection(t,e,this.corner[2],this.corner[3]),this.li.isProper()?!0:(this.li.hasIntersection()&&(i=!0),this.li.computeIntersection(t,e,this.corner[3],this.corner[0]),this.li.isProper()?!0:n&&i?!0:t.equals(this.pt)?!0:!!e.equals(this.pt))))},addSnappedNode:function(t,e){var n=t.getCoordinate(e),i=t.getCoordinate(e+1);return this.intersects(n,i)?(t.addIntersection(this.getCoordinate(),e),!0):!1},interfaces_:function(){return[]},getClass:function(){return lr}}),lr.SAFE_ENV_EXPANSION_FACTOR=.75,e(hr.prototype,{snap:function(){if(1===arguments.length){var t=arguments[0];return this.snap(t,null,-1)}if(3===arguments.length){var e=arguments[0],n=arguments[1],i=arguments[2],r=e.getSafeEnvelope(),s=new cr(e,n,i);return this.index.query(r,{interfaces_:function(){return[Ae]},visitItem:function(t){var e=t;e.select(r,s)}}),s.isNodeAdded()}},interfaces_:function(){return[]},getClass:function(){return hr}}),h(cr,hi),e(cr.prototype,{isNodeAdded:function(){return this._isNodeAdded},select:function(){if(2!==arguments.length)return hi.prototype.select.apply(this,arguments);var t=arguments[0],e=arguments[1],n=t.getContext();return null!==this.parentEdge&&n===this.parentEdge&&e===this.hotPixelVertexIndex?null:void(this._isNodeAdded=this.hotPixel.addSnappedNode(n,e))},interfaces_:function(){return[]},getClass:function(){return cr}}),hr.HotPixelSnapAction=cr,e(fr.prototype,{processIntersections:function(t,e,n,i){if(t===n&&e===i)return null;var r=t.getCoordinates()[e],s=t.getCoordinates()[e+1],o=n.getCoordinates()[i],a=n.getCoordinates()[i+1];if(this.li.computeIntersection(r,s,o,a),this.li.hasIntersection()&&this.li.isInteriorIntersection()){for(var u=0;u=0;t--){try{this.bufferReducedPrecision(t)}catch(e){if(!(e instanceof sn))throw e;this.saveException=e}finally{}if(null!==this.resultGeometry)return null}throw this.saveException}if(1===arguments.length){var n=arguments[0],i=dr.precisionScaleFactor(this.argGeom,this.distance,n),r=new ee(i);this.bufferFixedPrecision(r)}},computeGeometry:function(){if(this.bufferOriginalPrecision(),null!==this.resultGeometry)return null;var t=this.argGeom.getFactory().getPrecisionModel();t.getType()===ee.FIXED?this.bufferFixedPrecision(t):this.bufferReducedPrecision()},setQuadrantSegments:function(t){this.bufParams.setQuadrantSegments(t)},bufferOriginalPrecision:function(){try{var t=new ar(this.bufParams);this.resultGeometry=t.buffer(this.argGeom,this.distance)}catch(e){if(!(e instanceof l))throw e;this.saveException=e}finally{}},getResultGeometry:function(t){return this.distance=t,this.computeGeometry(),this.resultGeometry},setEndCapStyle:function(t){this.bufParams.setEndCapStyle(t)},interfaces_:function(){return[]},getClass:function(){return dr}}),dr.bufferOp=function(){if(2===arguments.length){var t=arguments[0],e=arguments[1],n=new dr(t),i=n.getResultGeometry(e);return i}if(3===arguments.length){if(Number.isInteger(arguments[2])&&arguments[0]instanceof B&&"number"==typeof arguments[1]){var r=arguments[0],s=arguments[1],o=arguments[2],a=new dr(r);a.setQuadrantSegments(o);var i=a.getResultGeometry(s);return i}if(arguments[2]instanceof Ki&&arguments[0]instanceof B&&"number"==typeof arguments[1]){var u=arguments[0],l=arguments[1],h=arguments[2],a=new dr(u,h),i=a.getResultGeometry(l);return i}}else if(4===arguments.length){var c=arguments[0],f=arguments[1],g=arguments[2],d=arguments[3],a=new dr(c);a.setQuadrantSegments(g),a.setEndCapStyle(d);var i=a.getResultGeometry(f);return i}},dr.precisionScaleFactor=function(t,e,n){var i=t.getEnvelopeInternal(),r=T.max(Math.abs(i.getMaxX()),Math.abs(i.getMaxY()),Math.abs(i.getMinX()),Math.abs(i.getMinY())),s=e>0?e:0,o=r+2*s,a=Math.trunc(Math.log(o)/Math.log(10)+1),u=n-a,l=Math.pow(10,u);return l},dr.CAP_ROUND=Ki.CAP_ROUND,dr.CAP_BUTT=Ki.CAP_FLAT,dr.CAP_FLAT=Ki.CAP_FLAT,dr.CAP_SQUARE=Ki.CAP_SQUARE,dr.MAX_PRECISION_DIGITS=12;var So=Object.freeze({BufferOp:dr,BufferParameters:Ki});e(pr.prototype,{filter:function(t){t instanceof Tt&&this.comps.add(t)},interfaces_:function(){return[ht]},getClass:function(){return pr}}),pr.getPolygons=function(){if(1===arguments.length){var t=arguments[0];return pr.getPolygons(t,new I)}if(2===arguments.length){var e=arguments[0],n=arguments[1];return e instanceof Tt?n.add(e):e instanceof ft&&e.apply(new pr(n)),n}},e(vr.prototype,{isInsideArea:function(){return this.segIndex===vr.INSIDE_AREA},getCoordinate:function(){return this.pt},getGeometryComponent:function(){return this.component},getSegmentIndex:function(){return this.segIndex},interfaces_:function(){return[]},getClass:function(){return vr}}),vr.INSIDE_AREA=-1,e(mr.prototype,{filter:function(t){t instanceof Lt&&this.pts.add(t)},interfaces_:function(){return[ht]},getClass:function(){return mr}}),mr.getPoints=function(){if(1===arguments.length){var t=arguments[0];return t instanceof Lt?ho.singletonList(t):mr.getPoints(t,new I)}if(2===arguments.length){var e=arguments[0],n=arguments[1];return e instanceof Lt?n.add(e):e instanceof ft&&e.apply(new mr(n)),n}},e(yr.prototype,{filter:function(t){(t instanceof Lt||t instanceof St||t instanceof Tt)&&this.locations.add(new vr(t,0,t.getCoordinate()))},interfaces_:function(){return[ht]},getClass:function(){return yr}}),yr.getLocations=function(t){var e=new I;return t.apply(new yr(e)),e},e(xr.prototype,{computeContainmentDistance:function(){if(0===arguments.length){var t=new Array(2).fill(null);if(this.computeContainmentDistance(0,t),this.minDistance<=this.terminateDistance)return null;this.computeContainmentDistance(1,t)}else if(2===arguments.length){var e=arguments[0],n=arguments[1],i=1-e,r=pr.getPolygons(this.geom[e]);if(r.size()>0){var s=yr.getLocations(this.geom[i]);if(this.computeContainmentDistance(s,r,n),this.minDistance<=this.terminateDistance)return this.minDistanceLocation[i]=n[0],this.minDistanceLocation[e]=n[1],null}}else if(3===arguments.length)if(arguments[2]instanceof Array&&R(arguments[0],y)&&R(arguments[1],y)){for(var o=arguments[0],a=arguments[1],u=arguments[2],l=0;lthis.minDistance)return null;for(var i=t.getCoordinates(),r=e.getCoordinate(),s=0;sthis.minDistance)return null;for(var i=l.getCoordinates(),f=h.getCoordinates(),s=0;st&&H.reverse(this.coordinates)}return this.coordinates},toLineString:function(){return this.factory.createLineString(this.getCoordinates())},add:function(t){this.directedEdges.add(t)},interfaces_:function(){return[]},getClass:function(){return Er}}),e(Ir.prototype,{setVisited:function(t){this._isVisited=t},isMarked:function(){return this._isMarked},setData:function(t){this.data=t},getData:function(){return this.data},setMarked:function(t){this._isMarked=t},getContext:function(){return this.data},isVisited:function(){return this._isVisited},setContext:function(t){this.data=t},interfaces_:function(){return[]},getClass:function(){return Ir}}),Ir.getComponentWithVisitedState=function(t,e){for(;t.hasNext();){var n=t.next();if(n.isVisited()===e)return n}return null},Ir.setVisited=function(t,e){for(;t.hasNext();){var n=t.next();n.setVisited(e)}},Ir.setMarked=function(t,e){for(;t.hasNext();){var n=t.next();n.setMarked(e)}},h(Nr,Ir),e(Nr.prototype,{isRemoved:function(){return null===this.parentEdge},compareDirection:function(t){return this.quadrant>t.quadrant?1:this.quadrants&&(s+=this.outEdges.size()),s}},add:function(t){this.outEdges.add(t),this.sorted=!1},getDegree:function(){return this.outEdges.size()},interfaces_:function(){return[]},getClass:function(){return wr}}),h(Lr,Ir),e(Lr.prototype,{isRemoved:function(){return null===this.pt},addOutEdge:function(t){this.deStar.add(t)},getCoordinate:function(){return this.pt},getOutEdges:function(){return this.deStar},remove:function(){if(0===arguments.length)this.pt=null;else if(1===arguments.length){var t=arguments[0];this.deStar.remove(t)}},getIndex:function(t){return this.deStar.getIndex(t)},getDegree:function(){return this.deStar.getDegree()},interfaces_:function(){return[]},getClass:function(){return Lr}}),Lr.getEdgesBetween=function(t,e){var n=Nr.toEdges(t.getOutEdges().getEdges()),i=new J(n),r=Nr.toEdges(e.getOutEdges().getEdges());return i.retainAll(r),i},h(Rr,Sr),e(Rr.prototype,{getLine:function(){return this.line},interfaces_:function(){return[]},getClass:function(){return Rr}}),e(Tr.prototype,{find:function(t){return this.nodeMap.get(t)},iterator:function(){return this.nodeMap.values().iterator()},remove:function(t){return this.nodeMap.remove(t)},values:function(){return this.nodeMap.values()},add:function(t){return this.nodeMap.put(t.getCoordinate(),t),t},interfaces_:function(){return[]},getClass:function(){return Tr}}),e(Pr.prototype,{findNodesOfDegree:function(t){for(var e=new I,n=this.nodeIterator();n.hasNext();){var i=n.next();i.getDegree()===t&&e.add(i)}return e},dirEdgeIterator:function(){return this.dirEdges.iterator()},edgeIterator:function(){return this.edges.iterator()},remove:function(){if(arguments[0]instanceof Sr){var t=arguments[0];this.remove(t.getDirEdge(0)),this.remove(t.getDirEdge(1)),this.edges.remove(t),t.remove()}else if(arguments[0]instanceof Nr){var e=arguments[0],n=e.getSym();null!==n&&n.setSym(null),e.getFromNode().remove(e),e.remove(),this.dirEdges.remove(e)}else if(arguments[0]instanceof Lr){for(var i=arguments[0],r=i.getOutEdges().getEdges(),s=r.iterator();s.hasNext();){var o=s.next(),n=o.getSym();null!==n&&this.remove(n),this.dirEdges.remove(o);var a=o.getEdge();null!==a&&this.edges.remove(a)}this.nodeMap.remove(i.getCoordinate()),i.remove()}},findNode:function(t){return this.nodeMap.find(t)},getEdges:function(){return this.edges},nodeIterator:function(){return this.nodeMap.iterator()},contains:function(){if(arguments[0]instanceof Sr){var t=arguments[0];return this.edges.contains(t)}if(arguments[0]instanceof Nr){var e=arguments[0];return this.dirEdges.contains(e)}},add:function(){if(arguments[0]instanceof Lr){var t=arguments[0];this.nodeMap.add(t)}else if(arguments[0]instanceof Sr){var e=arguments[0];this.edges.add(e),this.add(e.getDirEdge(0)),this.add(e.getDirEdge(1))}else if(arguments[0]instanceof Nr){var n=arguments[0];this.dirEdges.add(n)}},getNodes:function(){return this.nodeMap.values()},interfaces_:function(){return[]},getClass:function(){return Pr}}),h(br,Pr),e(br.prototype,{addEdge:function(t){if(t.isEmpty())return null;var e=H.removeRepeatedPoints(t.getCoordinates());if(e.length<=1)return null;var n=e[0],i=e[e.length-1],r=this.getNode(n),s=this.getNode(i),o=new Cr(r,s,e[1],!0),a=new Cr(s,r,e[e.length-2],!1),u=new Rr(t);u.setDirectedEdges(o,a),this.add(u)},getNode:function(t){var e=this.findNode(t);return null===e&&(e=new Lr(t),this.add(e)),e},interfaces_:function(){return[]},getClass:function(){return br}}),e(Or.prototype,{buildEdgeStringsForUnprocessedNodes:function(){for(var t=this.graph.getNodes().iterator();t.hasNext();){var e=t.next();e.isMarked()||(f.isTrue(2===e.getDegree()),this.buildEdgeStringsStartingAt(e),e.setMarked(!0))}},buildEdgeStringsForNonDegree2Nodes:function(){for(var t=this.graph.getNodes().iterator();t.hasNext();){var e=t.next();2!==e.getDegree()&&(this.buildEdgeStringsStartingAt(e),e.setMarked(!0))}},buildEdgeStringsForObviousStartNodes:function(){this.buildEdgeStringsForNonDegree2Nodes()},getMergedLineStrings:function(){return this.merge(),this.mergedLineStrings},buildEdgeStringsStartingAt:function(t){for(var e=t.getOutEdges().iterator();e.hasNext();){var n=e.next();n.getEdge().isMarked()||this.edgeStrings.add(this.buildEdgeStringStartingWith(n))}},merge:function(){if(null!==this.mergedLineStrings)return null;Ir.setMarked(this.graph.nodeIterator(),!1),Ir.setMarked(this.graph.edgeIterator(),!1),this.edgeStrings=new I,this.buildEdgeStringsForObviousStartNodes(),this.buildEdgeStringsForIsolatedLoops(),this.mergedLineStrings=new I;for(var t=this.edgeStrings.iterator();t.hasNext();){var e=t.next();this.mergedLineStrings.add(e.toLineString())}},buildEdgeStringStartingWith:function(t){var e=new Er(this.factory),n=t;do e.add(n),n.getEdge().setMarked(!0),n=n.getNext();while(null!==n&&n!==t);return e},add:function(){if(arguments[0]instanceof B){var t=arguments[0];t.apply({interfaces_:function(){return[q]},filter:function(t){t instanceof St&&this.add(t)}})}else if(R(arguments[0],v)){var e=arguments[0];this.mergedLineStrings=null;for(var n=e.iterator();n.hasNext();){var i=n.next();this.add(i)}}else if(arguments[0]instanceof St){var r=arguments[0];null===this.factory&&(this.factory=r.getFactory()),this.graph.addEdge(r)}},buildEdgeStringsForIsolatedLoops:function(){this.buildEdgeStringsForUnprocessedNodes()},interfaces_:function(){return[]},getClass:function(){return Or}});var Lo=Object.freeze({LineMerger:Or}),Ro=Object.freeze({OverlayOp:ii});h(_r,Nr),e(_r.prototype,{getNext:function(){return this.next},isInRing:function(){return null!==this.edgeRing},setRing:function(t){this.edgeRing=t},setLabel:function(t){this.label=t},getLabel:function(){return this.label},setNext:function(t){this.next=t},getRing:function(){return this.edgeRing},interfaces_:function(){return[]},getClass:function(){return _r}}),h(Mr,Sr),e(Mr.prototype,{getLine:function(){return this.line},interfaces_:function(){return[]},getClass:function(){return Mr}}),e(Dr.prototype,{isIncluded:function(){return this._isIncluded},getCoordinates:function(){if(null===this.ringPts){for(var t=new N,e=this.deList.iterator();e.hasNext();){var n=e.next(),i=n.getEdge();Dr.addEdge(i.getLine().getCoordinates(),n.getEdgeDirection(),t)}this.ringPts=t.toCoordinateArray()}return this.ringPts},isIncludedSet:function(){return this._isIncludedSet},isValid:function(){return this.getCoordinates(),this.ringPts.length<=3?!1:(this.getRing(),this.ring.isValid())},build:function(t){var e=t;do this.add(e),e.setRing(this),e=e.getNext(),f.isTrue(null!==e,"found null DE in ring"),f.isTrue(e===t||!e.isInRing(),"found DE already in ring");while(e!==t)},isOuterHole:function(){return this._isHole?!this.hasShell():!1},getPolygon:function(){var t=null;if(null!==this.holes){t=new Array(this.holes.size()).fill(null);for(var e=0;e=0;i--)n.add(t[i],!1)},Dr.findEdgeRingContaining=function(t,e){for(var n=t.getRing(),i=n.getEnvelopeInternal(),r=n.getCoordinateN(0),s=null,o=null,a=e.iterator();a.hasNext();){var u=a.next(),l=u.getRing(),h=l.getEnvelopeInternal();if(!h.equals(i)&&h.contains(i)){r=H.ptNotInList(n.getCoordinates(),l.getCoordinates());var c=!1;he.isPointInRing(r,l.getCoordinates())&&(c=!0),c&&(null===s||o.contains(h))&&(s=u,o=s.getRing().getEnvelopeInternal())}}return s},e(Ar.prototype,{compare:function(t,e){var n=t,i=e;return n.getRing().getEnvelope().compareTo(i.getRing().getEnvelope())},interfaces_:function(){return[a]},getClass:function(){return Ar}}),Dr.EnvelopeComparator=Ar,h(Fr,Pr),e(Fr.prototype,{findEdgeRing:function(t){var e=new Dr(this.factory);return e.build(t),e},computeDepthParity:function(){if(0===arguments.length)for(;;){var t=null;if(null===t)return null;this.computeDepthParity(t)}else if(1===arguments.length){arguments[0]}},computeNextCWEdges:function(){for(var t=this.nodeIterator();t.hasNext();){var e=t.next();Fr.computeNextCWEdges(e)}},addEdge:function(t){if(t.isEmpty())return null;var e=H.removeRepeatedPoints(t.getCoordinates());if(e.length<2)return null;var n=e[0],i=e[e.length-1],r=this.getNode(n),s=this.getNode(i),o=new _r(r,s,e[1],!0),a=new _r(s,r,e[e.length-2],!1),u=new Mr(t);u.setDirectedEdges(o,a),this.add(u)},deleteCutEdges:function(){this.computeNextCWEdges(),Fr.findLabeledEdgeRings(this.dirEdges);for(var t=new I,e=this.dirEdges.iterator();e.hasNext();){var n=e.next();if(!n.isMarked()){var i=n.getSym();if(n.getLabel()===i.getLabel()){n.setMarked(!0),i.setMarked(!0);var r=n.getEdge();t.add(r.getLine())}}}return t},getEdgeRings:function(){this.computeNextCWEdges(),Fr.label(this.dirEdges,-1);var t=Fr.findLabeledEdgeRings(this.dirEdges);this.convertMaximalToMinimalEdgeRings(t);for(var e=new I,n=this.dirEdges.iterator();n.hasNext();){var i=n.next();if(!i.isMarked()&&!i.isInRing()){var r=this.findEdgeRing(i);e.add(r)}}return e},getNode:function(t){var e=this.findNode(t);return null===e&&(e=new Lr(t),this.add(e)),e},convertMaximalToMinimalEdgeRings:function(t){for(var e=t.iterator();e.hasNext();){var n=e.next(),i=n.getLabel(),r=Fr.findIntersectionNodes(n,i);if(null!==r)for(var s=r.iterator();s.hasNext();){var o=s.next();Fr.computeNextCCWEdges(o,i)}}},deleteDangles:function(){for(var t=this.findNodesOfDegree(1),e=new J,n=new pe,i=t.iterator();i.hasNext();)n.push(i.next());for(;!n.isEmpty();){var r=n.pop();Fr.deleteAllEdges(r);for(var s=r.getOutEdges().getEdges(),i=s.iterator();i.hasNext();){var o=i.next();o.setMarked(!0);var a=o.getSym();null!==a&&a.setMarked(!0);var u=o.getEdge();e.add(u.getLine());var l=o.getToNode();1===Fr.getDegreeNonDeleted(l)&&n.push(l)}}return e},interfaces_:function(){return[]},getClass:function(){return Fr}}),Fr.findLabeledEdgeRings=function(t){for(var e=new I,n=1,i=t.iterator();i.hasNext();){var r=i.next();if(!(r.isMarked()||r.getLabel()>=0)){e.add(r);var s=Dr.findDirEdgesInRing(r);Fr.label(s,n),n++}}return e},Fr.getDegreeNonDeleted=function(t){for(var e=t.getOutEdges().getEdges(),n=0,i=e.iterator();i.hasNext();){var r=i.next();r.isMarked()||n++}return n},Fr.deleteAllEdges=function(t){for(var e=t.getOutEdges().getEdges(),n=e.iterator();n.hasNext();){var i=n.next();i.setMarked(!0);var r=i.getSym();null!==r&&r.setMarked(!0)}},Fr.label=function(t,e){for(var n=t.iterator();n.hasNext();){var i=n.next();i.setLabel(e)}},Fr.computeNextCWEdges=function(t){for(var e=t.getOutEdges(),n=null,i=null,r=e.getEdges().iterator();r.hasNext();){var s=r.next();if(!s.isMarked()){if(null===n&&(n=s),null!==i){var o=i.getSym();o.setNext(s)}i=s}}if(null!==i){var o=i.getSym();o.setNext(n)}},Fr.computeNextCCWEdges=function(t,e){for(var n=t.getOutEdges(),i=null,r=null,s=n.getEdges(),o=s.size()-1;o>=0;o--){var a=s.get(o),u=a.getSym(),l=null;a.getLabel()===e&&(l=a);var h=null;u.getLabel()===e&&(h=u),null===l&&null===h||(null!==h&&(r=h),null!==l&&(null!==r&&(r.setNext(l),r=null),null===i&&(i=l)))}null!==r&&(f.isTrue(null!==i),r.setNext(i))},Fr.getDegree=function(t,e){for(var n=t.getOutEdges().getEdges(),i=0,r=n.iterator();r.hasNext();){var s=r.next();s.getLabel()===e&&i++}return i},Fr.findIntersectionNodes=function(t,e){var n=t,i=null;do{var r=n.getFromNode();Fr.getDegree(r,e)>1&&(null===i&&(i=new I),i.add(r)),n=n.getNext(),f.isTrue(null!==n,"found null DE in ring"),f.isTrue(n===t||!n.isInRing(),"found DE already in ring")}while(n!==t);return i},e(Gr.prototype,{getGeometry:function(){return null===this.geomFactory&&(this.geomFactory=new ie),this.polygonize(),this.extractOnlyPolygonal?this.geomFactory.buildGeometry(this.polyList):this.geomFactory.createGeometryCollection(ie.toGeometryArray(this.polyList))},getInvalidRingLines:function(){return this.polygonize(),this.invalidRingLines},findValidRings:function(t,e,n){for(var i=t.iterator();i.hasNext();){var r=i.next();r.isValid()?e.add(r):n.add(r.getLineString())}},polygonize:function(){if(null!==this.polyList)return null;if(this.polyList=new I,null===this.graph)return null;this.dangles=this.graph.deleteDangles(),this.cutEdges=this.graph.deleteCutEdges();var t=this.graph.getEdgeRings(),e=new I;this.invalidRingLines=new I,this.isCheckingRingsValid?this.findValidRings(t,e,this.invalidRingLines):e=t,this.findShellsAndHoles(e),Gr.assignHolesToShells(this.holeList,this.shellList),ho.sort(this.shellList,new Dr.EnvelopeComparator);var n=!0;this.extractOnlyPolygonal&&(Gr.findDisjointShells(this.shellList),n=!1),this.polyList=Gr.extractPolygons(this.shellList,n)},getDangles:function(){return this.polygonize(),this.dangles},getCutEdges:function(){return this.polygonize(),this.cutEdges},getPolygons:function(){return this.polygonize(),this.polyList},add:function(){if(R(arguments[0],v))for(var t=arguments[0],e=t.iterator();e.hasNext();){var n=e.next();this.add(n)}else if(arguments[0]instanceof St){var i=arguments[0];this.geomFactory=i.getFactory(),null===this.graph&&(this.graph=new Fr(this.geomFactory)),this.graph.addEdge(i)}else if(arguments[0]instanceof B){var r=arguments[0];r.apply(this.lineStringAdder)}},setCheckRingsValid:function(t){this.isCheckingRingsValid=t},findShellsAndHoles:function(t){this.holeList=new I,this.shellList=new I;for(var e=t.iterator();e.hasNext();){var n=e.next();n.computeHole(),n.isHole()?this.holeList.add(n):this.shellList.add(n)}},interfaces_:function(){return[]},getClass:function(){return Gr}}),Gr.findOuterShells=function(t){for(var e=t.iterator();e.hasNext();){var n=e.next(),i=n.getOuterHole();null===i||i.isProcessed()||(n.setIncluded(!0),i.setProcessed(!0))}},Gr.extractPolygons=function(t,e){for(var n=new I,i=t.iterator();i.hasNext();){var r=i.next();(e||r.isIncluded())&&n.add(r.getPolygon())}return n},Gr.assignHolesToShells=function(t,e){for(var n=t.iterator();n.hasNext();){var i=n.next();Gr.assignHoleToShell(i,e)}},Gr.assignHoleToShell=function(t,e){var n=Dr.findEdgeRingContaining(t,e);null!==n&&n.addHole(t)},Gr.findDisjointShells=function(t){Gr.findOuterShells(t);var e=null;do{e=!1;for(var n=t.iterator();n.hasNext();){var i=n.next();i.isIncludedSet()||(i.updateIncluded(),i.isIncludedSet()||(e=!0))}}while(e)},e(qr.prototype,{filter:function(t){t instanceof St&&this.p.add(t)},interfaces_:function(){return[q]},getClass:function(){return qr}}),Gr.LineStringAdder=qr;var To=Object.freeze({Polygonizer:Gr});e(Br.prototype,{createEdgeEndForNext:function(t,e,n,i){var r=n.segmentIndex+1;if(r>=t.getNumPoints()&&null===i)return null;var s=t.getCoordinate(r);null!==i&&i.segmentIndex===n.segmentIndex&&(s=i.coord);var o=new En(t,n.coord,s,new gn(t.getLabel()));e.add(o)},createEdgeEndForPrev:function(t,e,n,i){var r=n.segmentIndex;if(0===n.dist){if(0===r)return null;r--}var s=t.getCoordinate(r);null!==i&&i.segmentIndex>=r&&(s=i.coord);var o=new gn(t.getLabel());o.flip();var a=new En(t,n.coord,s,o);e.add(a)},computeEdgeEnds:function(){if(1===arguments.length){for(var t=arguments[0],e=new I,n=t;n.hasNext();){var i=n.next();this.computeEdgeEnds(i,e)}return e}if(2===arguments.length){var r=arguments[0],s=arguments[1],o=r.getEdgeIntersectionList();o.addEndpoints();var a=o.iterator(),u=null,l=null;if(!a.hasNext())return null;var h=a.next();do u=l,l=h,h=null,a.hasNext()&&(h=a.next()),null!==l&&(this.createEdgeEndForPrev(r,s,l,u),this.createEdgeEndForNext(r,s,l,h));while(null!==l)}},interfaces_:function(){return[]},getClass:function(){return Br}}),h(zr,En),e(zr.prototype,{insert:function(t){this.edgeEnds.add(t)},print:function(t){t.println("EdgeEndBundle--> Label: "+this.label);for(var e=this.iterator();e.hasNext();){var n=e.next();n.print(t),t.println()}},iterator:function(){return this.edgeEnds.iterator()},getEdgeEnds:function(){return this.edgeEnds},computeLabelOn:function(t,e){for(var n=0,i=!1,r=this.iterator();r.hasNext();){var s=r.next(),o=s.getLabel().getLocation(t);o===L.BOUNDARY&&n++,o===L.INTERIOR&&(i=!0)}var o=L.NONE;i&&(o=L.INTERIOR),n>0&&(o=$n.determineBoundary(e,n)),this.label.setLocation(t,o)},computeLabelSide:function(t,e){for(var n=this.iterator();n.hasNext();){var i=n.next();if(i.getLabel().isArea()){var r=i.getLabel().getLocation(t,e);if(r===L.INTERIOR)return this.label.setLocation(t,e,L.INTERIOR),null;r===L.EXTERIOR&&this.label.setLocation(t,e,L.EXTERIOR)}}},getLabel:function(){return this.label},computeLabelSides:function(t){this.computeLabelSide(t,cn.LEFT),this.computeLabelSide(t,cn.RIGHT)},updateIM:function(t){Jn.updateIM(this.label,t)},computeLabel:function(t){for(var e=!1,n=this.iterator();n.hasNext();){var i=n.next();i.getLabel().isArea()&&(e=!0)}e?this.label=new gn(L.NONE,L.NONE,L.NONE):this.label=new gn(L.NONE);for(var r=0;2>r;r++)this.computeLabelOn(r,t),e&&this.computeLabelSides(r)},interfaces_:function(){return[]},getClass:function(){return zr}}),h(Vr,Pn),e(Vr.prototype,{updateIM:function(t){for(var e=this.iterator();e.hasNext();){var n=e.next();n.updateIM(t)}},insert:function(t){var e=this.edgeMap.get(t);null===e?(e=new zr(t),this.insertEdgeEnd(t,e)):e.insert(t)},interfaces_:function(){return[]},getClass:function(){return Vr}}),h(kr,yn),e(kr.prototype,{updateIMFromEdges:function(t){this.edges.updateIM(t)},computeIM:function(t){t.setAtLeastIfValid(this.label.getLocation(0),this.label.getLocation(1),0)},interfaces_:function(){return[]},getClass:function(){return kr}}),h(Yr,Nn),e(Yr.prototype,{createNode:function(t){return new kr(t,new Vr)},interfaces_:function(){return[]},getClass:function(){return Yr}}),e(Ur.prototype,{insertEdgeEnds:function(t){for(var e=t.iterator();e.hasNext();){var n=e.next();this.nodes.add(n)}},computeProperIntersectionIM:function(t,e){var n=this.arg[0].getGeometry().getDimension(),i=this.arg[1].getGeometry().getDimension(),r=t.hasProperIntersection(),s=t.hasProperInteriorIntersection();2===n&&2===i?r&&e.setAtLeast("212101212"):2===n&&1===i?(r&&e.setAtLeast("FFF0FFFF2"),s&&e.setAtLeast("1FFFFF1FF")):1===n&&2===i?(r&&e.setAtLeast("F0FFFFFF2"),s&&e.setAtLeast("1F1FFFFFF")):1===n&&1===i&&s&&e.setAtLeast("0FFFFFFFF")},labelIsolatedEdges:function(t,e){for(var n=this.arg[t].getEdgeIterator();n.hasNext();){var i=n.next();i.isIsolated()&&(this.labelIsolatedEdge(i,e,this.arg[e].getGeometry()),this.isolatedEdges.add(i))}},labelIsolatedEdge:function(t,e,n){if(n.getDimension()>0){var i=this.ptLocator.locate(t.getCoordinate(),n);t.getLabel().setAllLocations(e,i)}else t.getLabel().setAllLocations(e,L.EXTERIOR)},computeIM:function(){var t=new fe;if(t.set(L.EXTERIOR,L.EXTERIOR,2),!this.arg[0].getGeometry().getEnvelopeInternal().intersects(this.arg[1].getGeometry().getEnvelopeInternal()))return this.computeDisjointIM(t),t;this.arg[0].computeSelfNodes(this.li,!1),this.arg[1].computeSelfNodes(this.li,!1);var e=this.arg[0].computeEdgeIntersections(this.arg[1],this.li,!1);this.computeIntersectionNodes(0),this.computeIntersectionNodes(1),this.copyNodesAndLabels(0),this.copyNodesAndLabels(1),this.labelIsolatedNodes(),this.computeProperIntersectionIM(e,t);var n=new Br,i=n.computeEdgeEnds(this.arg[0].getEdgeIterator());this.insertEdgeEnds(i);var r=n.computeEdgeEnds(this.arg[1].getEdgeIterator());return this.insertEdgeEnds(r),this.labelNodeEdges(),this.labelIsolatedEdges(0,1),this.labelIsolatedEdges(1,0),this.updateIM(t),t},labelNodeEdges:function(){for(var t=this.nodes.iterator();t.hasNext();){var e=t.next();e.getEdges().computeLabelling(this.arg)}},copyNodesAndLabels:function(t){for(var e=this.arg[t].getNodeIterator();e.hasNext();){var n=e.next(),i=this.nodes.addNode(n.getCoordinate());i.setLabel(t,n.getLabel().getLocation(t))}},labelIntersectionNodes:function(t){for(var e=this.arg[t].getEdgeIterator();e.hasNext();)for(var n=e.next(),i=n.getLabel().getLocation(t),r=n.getEdgeIntersectionList().iterator();r.hasNext();){var s=r.next(),o=this.nodes.find(s.coord);o.getLabel().isNull(t)&&(i===L.BOUNDARY?o.setLabelBoundary(t):o.setLabel(t,L.INTERIOR))}},labelIsolatedNode:function(t,e){var n=this.ptLocator.locate(t.getCoordinate(),this.arg[e].getGeometry());t.getLabel().setAllLocations(e,n)},computeIntersectionNodes:function(t){for(var e=this.arg[t].getEdgeIterator();e.hasNext();)for(var n=e.next(),i=n.getLabel().getLocation(t),r=n.getEdgeIntersectionList().iterator();r.hasNext();){var s=r.next(),o=this.nodes.addNode(s.coord);i===L.BOUNDARY?o.setLabelBoundary(t):o.getLabel().isNull(t)&&o.setLabel(t,L.INTERIOR)}},labelIsolatedNodes:function(){for(var t=this.nodes.iterator();t.hasNext();){var e=t.next(),n=e.getLabel();f.isTrue(n.getGeometryCount()>0,"node with empty label found"),e.isIsolated()&&(n.isNull(0)?this.labelIsolatedNode(e,0):this.labelIsolatedNode(e,1))}},updateIM:function(t){for(var e=this.isolatedEdges.iterator();e.hasNext();){var n=e.next();n.updateIM(t)}for(var i=this.nodes.iterator();i.hasNext();){var r=i.next();r.updateIM(t),r.updateIMFromEdges(t)}},computeDisjointIM:function(t){var e=this.arg[0].getGeometry();e.isEmpty()||(t.set(L.INTERIOR,L.EXTERIOR,e.getDimension()),t.set(L.BOUNDARY,L.EXTERIOR,e.getBoundaryDimension()));var n=this.arg[1].getGeometry();n.isEmpty()||(t.set(L.EXTERIOR,L.INTERIOR,n.getDimension()),t.set(L.EXTERIOR,L.BOUNDARY,n.getBoundaryDimension()))},interfaces_:function(){return[]},getClass:function(){return Ur}}),e(Xr.prototype,{isContainedInBoundary:function(t){if(t instanceof Tt)return!1;if(t instanceof Lt)return this.isPointContainedInBoundary(t);if(t instanceof St)return this.isLineStringContainedInBoundary(t);for(var e=0;e0){var i=t;t=e,e=i}var r=!1;return e.y>t.y&&(r=!0),r?this.li.computeIntersection(t,e,this.diagDown0,this.diagDown1):this.li.computeIntersection(t,e,this.diagUp0,this.diagUp1),!!this.li.hasIntersection()},interfaces_:function(){return[]},getClass:function(){return Hr}}),e(Wr.prototype,{applyTo:function(t){for(var e=0;e=this.rectEnv.getMinX()&&e.getMaxX()<=this.rectEnv.getMaxX()?(this._intersects=!0,null):e.getMinY()>=this.rectEnv.getMinY()&&e.getMaxY()<=this.rectEnv.getMaxY()?(this._intersects=!0,null):void 0:null},intersects:function(){return this._intersects},interfaces_:function(){return[]},getClass:function(){return Kr}}),h(Zr,Wr),e(Zr.prototype,{isDone:function(){return this._containsPoint===!0},visit:function(t){if(!(t instanceof Tt))return null;var e=t.getEnvelopeInternal();if(!this.rectEnv.intersects(e))return null;for(var n=new g,i=0;4>i;i++)if(this.rectSeq.getCoordinate(i,n),e.contains(n)&&Tn.containsPointInPolygon(n,t))return this._containsPoint=!0,null},containsPoint:function(){return this._containsPoint},interfaces_:function(){return[]},getClass:function(){return Zr}}),h(Qr,Wr),e(Qr.prototype,{intersects:function(){return this.hasIntersection},isDone:function(){return this.hasIntersection===!0},visit:function(t){var e=t.getEnvelopeInternal();if(!this.rectEnv.intersects(e))return null;var n=kn.getLines(t);this.checkIntersectionWithLineStrings(n)},checkIntersectionWithLineStrings:function(t){for(var e=t.iterator();e.hasNext();){var n=e.next();if(this.checkIntersectionWithSegments(n),this.hasIntersection)return null}},checkIntersectionWithSegments:function(t){for(var e=t.getCoordinateSequence(),n=1;n=i-n){var r=ns.getGeometry(e,n);return this.unionSafe(r,null)}if(i-n===2)return this.unionSafe(ns.getGeometry(e,n),ns.getGeometry(e,n+1));var s=Math.trunc((i+n)/2),r=this.binaryUnion(e,n,s),o=this.binaryUnion(e,s,i);return this.unionSafe(r,o)}},repeatedUnion:function(t){for(var e=null,n=t.iterator();n.hasNext();){var i=n.next();e=null===e?i.copy():e.union(i)}return e},unionSafe:function(t,e){return null===t&&null===e?null:null===t?e.copy():null===e?t.copy():this.unionOptimized(t,e)},unionActual:function(t,e){return ns.restrictToPolygons(t.union(e))},unionTree:function(t){var e=this.reduceToGeometries(t),n=this.binaryUnion(e);return n},unionUsingEnvelopeIntersection:function(t,e,n){var i=new I,r=this.extractByEnvelope(n,t,i),s=this.extractByEnvelope(n,e,i),o=this.unionActual(r,s);i.add(o);var a=$r.combine(i);return a},bufferUnion:function(){if(1===arguments.length){var t=arguments[0],e=t.get(0).getFactory(),n=e.buildGeometry(t),i=n.buffer(0);return i}if(2===arguments.length){var r=arguments[0],s=arguments[1],e=r.getFactory(),n=e.createGeometryCollection([r,s]),i=n.buffer(0);return i}},interfaces_:function(){return[]},getClass:function(){return ns}}),ns.restrictToPolygons=function(t){if(R(t,Rt))return t;var e=pr.getPolygons(t);return 1===e.size()?e.get(0):t.getFactory().createMultiPolygon(ie.toPolygonArray(e))},ns.getGeometry=function(t,e){return e>=t.size()?null:t.get(e)},ns.union=function(t){var e=new ns(t);return e.union()},ns.STRTREE_NODE_CAPACITY=4,e(is.prototype,{unionNoOpt:function(t){var e=this.geomFact.createPoint();return si.overlayOp(t,e,ii.UNION)},unionWithNull:function(t,e){return null===t&&null===e?null:null===e?t:null===t?e:t.union(e)},extract:function(){if(R(arguments[0],v))for(var t=arguments[0],e=t.iterator();e.hasNext();){var n=e.next();this.extract(n)}else if(arguments[0]instanceof B){var i=arguments[0];null===this.geomFact&&(this.geomFact=i.getFactory()),es.extract(i,B.SORTINDEX_POLYGON,this.polygons),es.extract(i,B.SORTINDEX_LINESTRING,this.lines),es.extract(i,B.SORTINDEX_POINT,this.points)}},union:function Xo(){if(null===this.geomFact)return null;var t=null;if(this.points.size()>0){var e=this.geomFact.buildGeometry(this.points);t=this.unionNoOpt(e)}var n=null;if(this.lines.size()>0){var i=this.geomFact.buildGeometry(this.lines);n=this.unionNoOpt(i)}var r=null;this.polygons.size()>0&&(r=ns.union(this.polygons));var s=this.unionWithNull(n,r),Xo=null;return Xo=null===t?s:null===s?t:ts.union(t,s),null===Xo?this.geomFact.createGeometryCollection():Xo},interfaces_:function(){return[]},getClass:function(){return is}}),is.union=function(){if(1===arguments.length){if(R(arguments[0],v)){var t=arguments[0],e=new is(t);return e.union()}if(arguments[0]instanceof B){var n=arguments[0],e=new is(n);return e.union()}}else if(2===arguments.length){var i=arguments[0],r=arguments[1],e=new is(i,r);return e.union()}};var bo=Object.freeze({UnaryUnionOp:is});e(rs.prototype,{visitInteriorRing:function(t,e){var n=t.getCoordinates(),i=n[0],r=rs.findDifferentPoint(n,i),s=e.findEdgeInSameDirection(i,r),o=e.findEdgeEnd(s),a=null;o.getLabel().getLocation(0,cn.RIGHT)===L.INTERIOR?a=o:o.getSym().getLabel().getLocation(0,cn.RIGHT)===L.INTERIOR&&(a=o.getSym()),f.isTrue(null!==a,"unable to find dirEdge with Interior on RHS"),this.visitLinkedDirectedEdges(a)},visitShellInteriors:function(t,e){if(t instanceof Tt){var n=t;this.visitInteriorRing(n.getExteriorRing(),e)}if(t instanceof Ot)for(var i=t,r=0;r1)return this.invalidPoint=i.getEdge().getCoordinate(0),!0}return!1},isNodeConsistentArea:function(){var t=this.geomGraph.computeSelfNodes(this.li,!0,!0);return t.hasProperIntersection()?(this.invalidPoint=t.getProperIntersectionPoint(),!1):(this.nodeGraph.build(this.geomGraph),this.isNodeEdgeAreaLabelsConsistent())},interfaces_:function(){return[]},getClass:function(){return os}}),e(as.prototype,{buildIndex:function(){this.index=new ke;for(var t=0;t=1&&(e=t.getCoordinateN(0)),this.validErr=new us(us.RING_NOT_CLOSED,e)}},checkShellsNotNested:function(t,e){for(var n=0;n=2&&(i=!0);var r=e.edit(t,new hs(this.targetPM,i));return r},changePM:function(t,e){var n=this.createEditor(t.getFactory(),e);return n.edit(t,new _t.NoOpGeometryOperation)},setRemoveCollapsedComponents:function(t){this.removeCollapsed=t},createFactory:function(t,e){var n=new ie(e,t.getSRID(),t.getCoordinateSequenceFactory());return n},setChangePrecisionModel:function(t){this.changePrecisionModel=t},reduce:function(t){var e=this.reducePointwise(t);return this.isPointwise?e:R(e,Rt)?e.isValid()?e:this.fixPolygonalTopology(e):e},setPointwise:function(t){this.isPointwise=t},createEditor:function(t,e){if(t.getPrecisionModel()===e)return new _t;var n=this.createFactory(t,e),i=new _t(n);return i},interfaces_:function(){return[]},getClass:function(){return cs}}),cs.reduce=function(t,e){var n=new cs(e);return n.reduce(t)},cs.reducePointwise=function(t,e){var n=new cs(e);return n.setPointwise(!0),n.reduce(t)};var Mo=Object.freeze({GeometryPrecisionReducer:cs});e(fs.prototype,{simplifySection:function(t,e){if(t+1===e)return null;this.seg.p0=this.pts[t],this.seg.p1=this.pts[e];for(var n=-1,i=t,r=t+1;e>r;r++){var s=this.seg.distance(this.pts[r]);s>n&&(n=s,i=r)}if(n<=this.distanceTolerance)for(var r=t+1;e>r;r++)this.usePt[r]=!1;else this.simplifySection(t,i),this.simplifySection(i,e)},setDistanceTolerance:function(t){this.distanceTolerance=t},simplify:function(){this.usePt=new Array(this.pts.length).fill(null);for(var t=0;tt)throw new i("Tolerance must be non-negative");this.distanceTolerance=t},interfaces_:function(){return[]},getClass:function(){return gs}}),gs.simplify=function(t,e){var n=new gs(t);return n.setDistanceTolerance(e),n.getResultGeometry()},h(ds,xe),e(ds.prototype,{transformPolygon:function(t,e){if(t.isEmpty())return null;var n=xe.prototype.transformPolygon.call(this,t,e);return e instanceof Ot?n:this.createValidArea(n)},createValidArea:function(t){return this.isEnsureValidTopology?t.buffer(0):t},transformCoordinates:function(t,e){var n=t.toCoordinateArray(),i=null;return i=0===n.length?new Array(0).fill(null):fs.simplify(n,this.distanceTolerance),this.factory.getCoordinateSequenceFactory().create(i)},transformMultiPolygon:function(t,e){var n=xe.prototype.transformMultiPolygon.call(this,t,e);return this.createValidArea(n)},transformLinearRing:function(t,e){var n=e instanceof Tt,i=xe.prototype.transformLinearRing.call(this,t,e);return!n||i instanceof bt?i:null},interfaces_:function(){return[]},getClass:function(){return ds}}),gs.DPTransformer=ds,h(ps,ce),e(ps.prototype,{getIndex:function(){return this.index},getParent:function(){return this.parent},interfaces_:function(){return[]},getClass:function(){return ps}}),e(vs.prototype,{addToResult:function(t){this.resultSegs.add(t)},asLineString:function(){return this.parentLine.getFactory().createLineString(vs.extractCoordinates(this.resultSegs))},getResultSize:function(){var t=this.resultSegs.size();return 0===t?0:t+1},getParent:function(){return this.parentLine},getSegment:function(t){return this.segs[t]},getParentCoordinates:function(){return this.parentLine.getCoordinates()},getMinimumSize:function(){return this.minimumSize},asLinearRing:function(){return this.parentLine.getFactory().createLinearRing(vs.extractCoordinates(this.resultSegs))},getSegments:function(){return this.segs},init:function(){var t=this.parentLine.getCoordinates();this.segs=new Array(t.length-1).fill(null);for(var e=0;ethis.distanceTolerance&&(s=!1);var l=new ce;if(l.p0=this.linePts[t],l.p1=this.linePts[e],i[0]=t,i[1]=e,this.hasBadIntersection(this.line,i,l)&&(s=!1),s){var r=this.flatten(t,e);return this.line.addToResult(r),null}this.simplifySection(t,u,n),this.simplifySection(u,e,n)},hasBadOutputIntersection:function(t){for(var e=this.outputIndex.query(t),n=e.iterator();n.hasNext();){var i=n.next();if(this.hasInteriorIntersection(i,t))return!0}return!1},findFurthestPoint:function(t,e,n,i){var r=new ce;r.p0=t[e],r.p1=t[n];for(var s=-1,o=e,a=e+1;n>a;a++){var u=t[a],l=r.distance(u);l>s&&(s=l,o=a)}return i[0]=s,o},simplify:function(t){this.line=t,this.linePts=t.getParentCoordinates(),this.simplifySection(0,this.linePts.length-1,0)},remove:function(t,e,n){for(var i=e;n>i;i++){var r=t.getSegment(i);this.inputIndex.remove(r)}},hasInteriorIntersection:function(t,e){return this.li.computeIntersection(t.p0,t.p1,e.p0,e.p1),this.li.isInteriorIntersection()},hasBadInputIntersection:function(t,e,n){for(var i=this.inputIndex.query(n),r=i.iterator();r.hasNext();){var s=r.next();if(this.hasInteriorIntersection(s,n)){if(xs.isInLineSection(t,e,s))continue;return!0}}return!1},interfaces_:function(){return[]},getClass:function(){return xs}}),xs.isInLineSection=function(t,e,n){if(n.getParent()!==t.getParent())return!1;var i=n.getIndex();return i>=e[0]&&it)throw new i("Tolerance must be non-negative");this.lineSimplifier.setDistanceTolerance(t)},interfaces_:function(){return[]},getClass:function(){return Is}}),Is.simplify=function(t,e){var n=new Is(t);return n.setDistanceTolerance(e),n.getResultGeometry()},h(Ns,xe),e(Ns.prototype,{transformCoordinates:function(t,e){if(0===t.size())return null;if(e instanceof St){var n=this.linestringMap.get(e);return this.createCoordinateSequence(n.getResultCoordinates())}return xe.prototype.transformCoordinates.call(this,t,e)},interfaces_:function(){return[]},getClass:function(){return Ns}}),e(Cs.prototype,{filter:function(t){if(t instanceof St){var e=t;if(e.isEmpty())return null;var n=e.isClosed()?4:2,i=new vs(e,n);this.tps.linestringMap.put(e,i)}},interfaces_:function(){return[q]},getClass:function(){return Cs}}),Is.LineStringTransformer=Ns,Is.LineStringMapBuilderFilter=Cs;var Do=Object.freeze({DouglasPeuckerSimplifier:gs,TopologyPreservingSimplifier:Is});e(Ss.prototype,{splitAt:function(){if(1===arguments.length){var t=arguments[0],e=this.minimumLen/this.segLen;if(t.distance(this.seg.p0)r&&(u=r),s.setMinimumLength(u),s.splitAt(o),s.getSplitPoint()},interfaces_:function(){return[ws]},getClass:function(){return Ls}}),Ls.projectedSplitPoint=function(t,e){var n=t.getLineSegment(),i=n.project(e);return i},e(Rs.prototype,{interfaces_:function(){return[]},getClass:function(){return Rs}}),Rs.triArea=function(t,e,n){return(e.x-t.x)*(n.y-t.y)-(e.y-t.y)*(n.x-t.x)},Rs.isInCircleDDNormalized=function(t,e,n,i){var r=_.valueOf(t.x).selfSubtract(i.x),s=_.valueOf(t.y).selfSubtract(i.y),o=_.valueOf(e.x).selfSubtract(i.x),a=_.valueOf(e.y).selfSubtract(i.y),u=_.valueOf(n.x).selfSubtract(i.x),l=_.valueOf(n.y).selfSubtract(i.y),h=r.multiply(a).selfSubtract(o.multiply(s)),c=o.multiply(l).selfSubtract(u.multiply(a)),f=u.multiply(s).selfSubtract(r.multiply(l)),g=r.multiply(r).selfAdd(s.multiply(s)),d=o.multiply(o).selfAdd(a.multiply(a)),p=u.multiply(u).selfAdd(l.multiply(l)),v=g.selfMultiply(c).selfAdd(d.selfMultiply(f)).selfAdd(p.selfMultiply(h)),m=v.doubleValue()>0;return m},Rs.checkRobustInCircle=function(t,e,n,i){var r=Rs.isInCircleNonRobust(t,e,n,i),s=Rs.isInCircleDDSlow(t,e,n,i),o=Rs.isInCircleCC(t,e,n,i),a=Si.circumcentre(t,e,n);A.out.println("p radius diff a = "+Math.abs(i.distance(a)-t.distance(a))/t.distance(a)),r===s&&r===o||(A.out.println("inCircle robustness failure (double result = "+r+", DD result = "+s+", CC result = "+o+")"),A.out.println(se.toLineString(new Gt([t,e,n,i]))),A.out.println("Circumcentre = "+se.toPoint(a)+" radius = "+t.distance(a)),A.out.println("p radius diff a = "+Math.abs(i.distance(a)/t.distance(a)-1)),A.out.println("p radius diff b = "+Math.abs(i.distance(a)/e.distance(a)-1)),A.out.println("p radius diff c = "+Math.abs(i.distance(a)/n.distance(a)-1)),A.out.println())},Rs.isInCircleDDFast=function(t,e,n,i){var r=_.sqr(t.x).selfAdd(_.sqr(t.y)).selfMultiply(Rs.triAreaDDFast(e,n,i)),s=_.sqr(e.x).selfAdd(_.sqr(e.y)).selfMultiply(Rs.triAreaDDFast(t,n,i)),o=_.sqr(n.x).selfAdd(_.sqr(n.y)).selfMultiply(Rs.triAreaDDFast(t,e,i)),a=_.sqr(i.x).selfAdd(_.sqr(i.y)).selfMultiply(Rs.triAreaDDFast(t,e,n)),u=r.selfSubtract(s).selfAdd(o).selfSubtract(a),l=u.doubleValue()>0;return l},Rs.isInCircleCC=function(t,e,n,i){var r=Si.circumcentre(t,e,n),s=t.distance(r),o=i.distance(r)-s;return 0>=o},Rs.isInCircleNormalized=function(t,e,n,i){var r=t.x-i.x,s=t.y-i.y,o=e.x-i.x,a=e.y-i.y,u=n.x-i.x,l=n.y-i.y,h=r*a-o*s,c=o*l-u*a,f=u*s-r*l,g=r*r+s*s,d=o*o+a*a,p=u*u+l*l,v=g*c+d*f+p*h;return v>0},Rs.isInCircleDDSlow=function(t,e,n,i){var r=_.valueOf(i.x),s=_.valueOf(i.y),o=_.valueOf(t.x),a=_.valueOf(t.y),u=_.valueOf(e.x),l=_.valueOf(e.y),h=_.valueOf(n.x),c=_.valueOf(n.y),f=o.multiply(o).add(a.multiply(a)).multiply(Rs.triAreaDDSlow(u,l,h,c,r,s)),g=u.multiply(u).add(l.multiply(l)).multiply(Rs.triAreaDDSlow(o,a,h,c,r,s)),d=h.multiply(h).add(c.multiply(c)).multiply(Rs.triAreaDDSlow(o,a,u,l,r,s)),p=r.multiply(r).add(s.multiply(s)).multiply(Rs.triAreaDDSlow(o,a,u,l,h,c)),v=f.subtract(g).add(d).subtract(p),m=v.doubleValue()>0; +return m},Rs.isInCircleNonRobust=function(t,e,n,i){var r=(t.x*t.x+t.y*t.y)*Rs.triArea(e,n,i)-(e.x*e.x+e.y*e.y)*Rs.triArea(t,n,i)+(n.x*n.x+n.y*n.y)*Rs.triArea(t,e,i)-(i.x*i.x+i.y*i.y)*Rs.triArea(t,e,n)>0;return r},Rs.isInCircleRobust=function(t,e,n,i){return Rs.isInCircleNormalized(t,e,n,i)},Rs.triAreaDDSlow=function(t,e,n,i,r,s){return n.subtract(t).multiply(s.subtract(e)).subtract(i.subtract(e).multiply(r.subtract(t)))},Rs.triAreaDDFast=function(t,e,n){var i=_.valueOf(e.x).selfSubtract(t.x).selfMultiply(_.valueOf(n.y).selfSubtract(t.y)),r=_.valueOf(e.y).selfSubtract(t.y).selfMultiply(_.valueOf(n.x).selfSubtract(t.x));return i.selfSubtract(r)},e(Ts.prototype,{circleCenter:function(t,e){var n=new Ts(this.getX(),this.getY()),i=this.bisector(n,t),r=this.bisector(t,e),s=new F(i,r),o=null;try{o=new Ts(s.getX(),s.getY())}catch(a){if(!(a instanceof w))throw a;A.err.println("a: "+n+" b: "+t+" c: "+e),A.err.println(a)}finally{}return o},dot:function(t){return this.p.x*t.getX()+this.p.y*t.getY()},magn:function(){return Math.sqrt(this.p.x*this.p.x+this.p.y*this.p.y)},getZ:function(){return this.p.z},bisector:function(t,e){var n=e.getX()-t.getX(),i=e.getY()-t.getY(),r=new F(t.getX()+n/2,t.getY()+i/2,1),s=new F(t.getX()-i+n/2,t.getY()+n+i/2,1);return new F(r,s)},equals:function(){if(1===arguments.length){var t=arguments[0];return this.p.x===t.getX()&&this.p.y===t.getY()}if(2===arguments.length){var e=arguments[0],n=arguments[1];return this.p.distance(e.getCoordinate())0},getX:function(){return this.p.x},crossProduct:function(t){return this.p.x*t.getY()-this.p.y*t.getX()},setZ:function(t){this.p.z=t},times:function(t){return new Ts(t*this.p.x,t*this.p.y)},cross:function(){return new Ts(this.p.y,-this.p.x)},leftOf:function(t){return this.isCCW(t.orig(),t.dest())},toString:function(){return"POINT ("+this.p.x+" "+this.p.y+")"},sub:function(t){return new Ts(this.p.x-t.getX(),this.p.y-t.getY())},getY:function(){return this.p.y},classify:function(t,e){var n=this,i=e.sub(t),r=n.sub(t),s=i.crossProduct(r);return s>0?Ts.LEFT:0>s?Ts.RIGHT:i.getX()*r.getX()<0||i.getY()*r.getY()<0?Ts.BEHIND:i.magn()s&&(r=s),s=this.distance(e,this),r>s&&(r=s),i/r},interfaces_:function(){return[]},getClass:function(){return Ts}}),Ts.interpolateZ=function(){if(3===arguments.length){var t=arguments[0],e=arguments[1],n=arguments[2],i=e.distance(n),r=t.distance(e),s=n.z-e.z,o=e.z+s*(r/i);return o}if(4===arguments.length){var a=arguments[0],u=arguments[1],l=arguments[2],h=arguments[3],c=u.x,f=u.y,g=l.x-c,d=h.x-c,p=l.y-f,v=h.y-f,m=g*v-d*p,y=a.x-c,x=a.y-f,E=(v*y-d*x)/m,I=(-p*y+g*x)/m,N=u.z+E*(l.z-u.z)+I*(h.z-u.z);return N}},Ts.LEFT=0,Ts.RIGHT=1,Ts.BEYOND=2,Ts.BEHIND=3,Ts.BETWEEN=4,Ts.ORIGIN=5,Ts.DESTINATION=6,h(Ps,Ts),e(Ps.prototype,{getConstraint:function(){return this.constraint},setOnConstraint:function(t){this._isOnConstraint=t},merge:function(t){t._isOnConstraint&&(this._isOnConstraint=!0,this.constraint=t.constraint)},isOnConstraint:function(){return this._isOnConstraint},setConstraint:function(t){this._isOnConstraint=!0,this.constraint=t},interfaces_:function(){return[]},getClass:function(){return Ps}}),e(bs.prototype,{equalsNonOriented:function(t){return this.equalsOriented(t)?!0:!!this.equalsOriented(t.sym())},toLineSegment:function(){return new ce(this.vertex.getCoordinate(),this.dest().getCoordinate())},dest:function(){return this.sym().orig()},oNext:function(){return this.next},equalsOriented:function(t){return!(!this.orig().getCoordinate().equals2D(t.orig().getCoordinate())||!this.dest().getCoordinate().equals2D(t.dest().getCoordinate()))},dNext:function(){return this.sym().oNext().sym()},lPrev:function(){return this.next.sym()},rPrev:function(){return this.sym().oNext()},rot:function(){return this._rot},oPrev:function(){return this._rot.next._rot},sym:function(){return this._rot._rot},setOrig:function(t){this.vertex=t},lNext:function(){return this.invRot().oNext().rot()},getLength:function(){return this.orig().getCoordinate().distance(this.dest().getCoordinate())},invRot:function(){return this._rot.sym()},setDest:function(t){this.sym().setOrig(t)},setData:function(t){this.data=t},getData:function(){return this.data},"delete":function(){this._rot=null},orig:function(){return this.vertex},rNext:function(){return this._rot.next.invRot()},toString:function(){var t=this.vertex.getCoordinate(),e=this.dest().getCoordinate();return se.toLineString(t,e)},isLive:function(){return null!==this._rot},getPrimary:function(){return this.orig().getCoordinate().compareTo(this.dest().getCoordinate())<=0?this:this.sym()},dPrev:function(){return this.invRot().oNext().invRot()},setNext:function(t){this.next=t},interfaces_:function(){return[]},getClass:function(){return bs}}),bs.makeEdge=function(t,e){var n=new bs,i=new bs,r=new bs,s=new bs;n._rot=i,i._rot=r,r._rot=s,s._rot=n,n.setNext(n),i.setNext(s),r.setNext(r),s.setNext(i);var o=n;return o.setOrig(t),o.setDest(e),o},bs.swap=function(t){var e=t.oPrev(),n=t.sym().oPrev();bs.splice(t,e),bs.splice(t.sym(),n),bs.splice(t,e.lNext()),bs.splice(t.sym(),n.lNext()),t.setOrig(e.dest()),t.setDest(n.dest())},bs.splice=function(t,e){var n=t.oNext().rot(),i=e.oNext().rot(),r=e.oNext(),s=t.oNext(),o=i.oNext(),a=n.oNext();t.setNext(r),e.setNext(s),n.setNext(o),i.setNext(a)},bs.connect=function(t,e){var n=bs.makeEdge(t.dest(),e.orig());return bs.splice(n,t.lNext()),bs.splice(n.sym(),e),n},e(Os.prototype,{insertSite:function(t){var e=this.subdiv.locate(t);if(this.subdiv.isVertexOfEdge(e,t))return e;this.subdiv.isOnEdge(e,t.getCoordinate())&&(e=e.oPrev(),this.subdiv["delete"](e.oNext()));var n=this.subdiv.makeEdge(e.orig(),t);bs.splice(n,e);var i=n;do n=this.subdiv.connect(e,n.sym()),e=n.oPrev();while(e.lNext()!==i);for(;;){var r=e.oPrev();if(r.dest().rightOf(e)&&t.isInCircle(e.orig(),r.dest(),e.dest()))bs.swap(e),e=e.oPrev();else{if(e.oNext()===i)return n;e=e.oNext().lPrev()}}},insertSites:function(t){for(var e=t.iterator();e.hasNext();){var n=e.next();this.insertSite(n)}},interfaces_:function(){return[]},getClass:function(){return Os}}),e(_s.prototype,{locate:function(t){},interfaces_:function(){return[]},getClass:function(){return _s}}),e(Ms.prototype,{init:function(){this.lastEdge=this.findEdge()},locate:function(t){this.lastEdge.isLive()||this.init();var e=this.subdiv.locateFromEdge(t,this.lastEdge);return this.lastEdge=e,e},findEdge:function(){var t=this.subdiv.getEdges();return t.iterator().next()},interfaces_:function(){return[_s]},getClass:function(){return Ms}}),h(Ds,l),e(Ds.prototype,{getSegment:function(){return this.seg},interfaces_:function(){return[]},getClass:function(){return Ds}}),Ds.msgWithSpatial=function(t,e){return null!==e?t+" [ "+e+" ]":t},e(As.prototype,{visit:function(t){},interfaces_:function(){return[]},getClass:function(){return As}}),e(Fs.prototype,{getTriangleVertices:function(t){var e=new Bs;return this.visitTriangles(e,t),e.getTriangleVertices()},isFrameVertex:function(t){return t.equals(this.frameVertex[0])?!0:t.equals(this.frameVertex[1])?!0:!!t.equals(this.frameVertex[2])},isVertexOfEdge:function(t,e){return!(!e.equals(t.orig(),this.tolerance)&&!e.equals(t.dest(),this.tolerance))},connect:function(t,e){var n=bs.connect(t,e);return this.quadEdges.add(n),n},getVoronoiCellPolygon:function(t,e){var n=new I,i=t;do{var r=t.rot().orig().getCoordinate();n.add(r),t=t.oPrev()}while(t!==i);var s=new N;s.addAll(n,!1),s.closeRing(),s.size()<4&&(A.out.println(s),s.add(s.get(s.size()-1),!0));var o=s.toCoordinateArray(),a=e.createPolygon(e.createLinearRing(o),null),u=i.orig();return a.setUserData(u.getCoordinate()),a},setLocator:function(t){this.locator=t},initSubdiv:function(){var t=this.makeEdge(this.frameVertex[0],this.frameVertex[1]),e=this.makeEdge(this.frameVertex[1],this.frameVertex[2]);bs.splice(t.sym(),e);var n=this.makeEdge(this.frameVertex[2],this.frameVertex[0]);return bs.splice(e.sym(),n),bs.splice(n.sym(),t),t},isFrameBorderEdge:function(t){var e=new Array(3).fill(null);Fs.getTriangleEdges(t,e);var n=new Array(3).fill(null);Fs.getTriangleEdges(t.sym(),n);var i=t.lNext().dest();if(this.isFrameVertex(i))return!0;var r=t.sym().lNext().dest();return!!this.isFrameVertex(r)},makeEdge:function(t,e){var n=bs.makeEdge(t,e);return this.quadEdges.add(n),n},visitTriangles:function(t,e){this.visitedKey++;var n=new pe;n.push(this.startingEdge);for(var i=new J;!n.empty();){var r=n.pop();if(!i.contains(r)){var s=this.fetchTriangleToVisit(r,n,e,i);null!==s&&t.visit(s)}}},isFrameEdge:function(t){return!(!this.isFrameVertex(t.orig())&&!this.isFrameVertex(t.dest()))},isOnEdge:function(t,e){this.seg.setCoordinates(t.orig().getCoordinate(),t.dest().getCoordinate());var n=this.seg.distance(e);return nn?10*e:10*n,this.frameVertex[0]=new Ts((t.getMaxX()+t.getMinX())/2,t.getMaxY()+i),this.frameVertex[1]=new Ts(t.getMinX()-i,t.getMinY()-i),this.frameVertex[2]=new Ts(t.getMaxX()+i,t.getMinY()-i),this.frameEnv=new C(this.frameVertex[0].getCoordinate(),this.frameVertex[1].getCoordinate()),this.frameEnv.expandToInclude(this.frameVertex[2].getCoordinate())},getTriangleCoordinates:function(t){var e=new zs;return this.visitTriangles(e,t),e.getTriangles()},getVertices:function(t){for(var e=new J,n=this.quadEdges.iterator();n.hasNext();){var i=n.next(),r=i.orig();!t&&this.isFrameVertex(r)||e.add(r);var s=i.dest();!t&&this.isFrameVertex(s)||e.add(s)}return e},fetchTriangleToVisit:function(t,e,n,i){var r=t,s=0,o=!1;do{this.triEdges[s]=r,this.isFrameEdge(r)&&(o=!0);var a=r.sym();i.contains(a)||e.push(a),i.add(r),s++,r=r.lNext()}while(r!==t);return o&&!n?null:this.triEdges},getEdges:function(){if(0===arguments.length)return this.quadEdges;if(1===arguments.length){for(var t=arguments[0],e=this.getPrimaryEdges(!1),n=new Array(e.size()).fill(null),i=0,r=e.iterator();r.hasNext();){var s=r.next();n[i++]=t.createLineString([s.orig().getCoordinate(),s.dest().getCoordinate()])}return t.createMultiLineString(n)}},getVertexUniqueEdges:function(t){for(var e=new I,n=new J,i=this.quadEdges.iterator();i.hasNext();){var r=i.next(),s=r.orig();n.contains(s)||(n.add(s),!t&&this.isFrameVertex(s)||e.add(r));var o=r.sym(),a=o.orig();n.contains(a)||(n.add(a),!t&&this.isFrameVertex(a)||e.add(o))}return e},getTriangleEdges:function(t){var e=new qs;return this.visitTriangles(e,t),e.getTriangleEdges()},getPrimaryEdges:function(t){this.visitedKey++;var e=new I,n=new pe;n.push(this.startingEdge);for(var i=new J;!n.empty();){var r=n.pop();if(!i.contains(r)){var s=r.getPrimary();!t&&this.isFrameEdge(s)||e.add(s),n.push(r.oNext()),n.push(r.sym().oNext()),i.add(r),i.add(r.sym())}}return e},"delete":function(t){bs.splice(t,t.oPrev()),bs.splice(t.sym(),t.sym().oPrev());var e=t.sym(),n=t.rot(),i=t.rot().sym();this.quadEdges.remove(t),this.quadEdges.remove(e),this.quadEdges.remove(n),this.quadEdges.remove(i),t["delete"](),e["delete"](),n["delete"](),i["delete"]()},locateFromEdge:function(t,e){for(var n=0,i=this.quadEdges.size(),r=e;;){if(n++,n>i)throw new Ds(r.toLineSegment());if(t.equals(r.orig())||t.equals(r.dest()))break;if(t.rightOf(r))r=r.sym();else if(t.rightOf(r.oNext())){if(t.rightOf(r.dPrev()))break;r=r.dPrev()}else r=r.oNext()}return r},getTolerance:function(){return this.tolerance},getVoronoiCellPolygons:function(t){this.visitTriangles(new Gs,!0);for(var e=new I,n=this.getVertexUniqueEdges(!1),i=n.iterator();i.hasNext();){var r=i.next();e.add(this.getVoronoiCellPolygon(r,t))}return e},getVoronoiDiagram:function(t){var e=this.getVoronoiCellPolygons(t);return t.createGeometryCollection(ie.toGeometryArray(e))},getTriangles:function(t){for(var e=this.getTriangleCoordinates(!1),n=new Array(e.size()).fill(null),i=0,r=e.iterator();r.hasNext();){var s=r.next();n[i++]=t.createPolygon(t.createLinearRing(s),null)}return t.createGeometryCollection(n)},insertSite:function(t){var e=this.locate(t);if(t.equals(e.orig(),this.tolerance)||t.equals(e.dest(),this.tolerance))return e;var n=this.makeEdge(e.orig(),t);bs.splice(n,e);var i=n;do n=this.connect(e,n.sym()),e=n.oPrev();while(e.lNext()!==i);return i},locate:function(){if(1===arguments.length){if(arguments[0]instanceof Ts){var t=arguments[0];return this.locator.locate(t)}if(arguments[0]instanceof g){var e=arguments[0];return this.locator.locate(new Ts(e))}}else if(2===arguments.length){var n=arguments[0],i=arguments[1],r=this.locator.locate(new Ts(n));if(null===r)return null;var s=r;r.dest().getCoordinate().equals2D(n)&&(s=r.sym());var o=s;do{if(o.dest().getCoordinate().equals2D(i))return o;o=o.oNext()}while(o!==s);return null}},interfaces_:function(){return[]},getClass:function(){return Fs}}),Fs.getTriangleEdges=function(t,e){if(e[0]=t,e[1]=e[0].lNext(),e[2]=e[1].lNext(),e[2].lNext()!==e[0])throw new i("Edges do not form a triangle")},e(Gs.prototype,{visit:function(t){for(var e=t[0].orig().getCoordinate(),n=t[1].orig().getCoordinate(),i=t[2].orig().getCoordinate(),r=Si.circumcentre(e,n,i),s=new Ts(r),o=0;3>o;o++)t[o].rot().setOrig(s)},interfaces_:function(){return[As]},getClass:function(){return Gs}}),e(qs.prototype,{getTriangleEdges:function(){return this.triList},visit:function(t){this.triList.add(t.clone())},interfaces_:function(){return[As]},getClass:function(){return qs}}),e(Bs.prototype,{visit:function(t){this.triList.add([t[0].orig(),t[1].orig(),t[2].orig()])},getTriangleVertices:function(){return this.triList},interfaces_:function(){return[As]},getClass:function(){return Bs}}),e(zs.prototype,{checkTriangleSize:function(t){var e="";t.length>=2?e=se.toLineString(t[0],t[1]):t.length>=1&&(e=se.toPoint(t[0]))},visit:function(t){this.coordList.clear();for(var e=0;3>e;e++){var n=t[e].orig();this.coordList.add(n.getCoordinate())}if(this.coordList.size()>0){this.coordList.closeRing();var i=this.coordList.toCoordinateArray();if(4!==i.length)return null;this.triCoords.add(i)}},getTriangles:function(){return this.triCoords},interfaces_:function(){return[As]},getClass:function(){return zs}}),Fs.TriangleCircumcentreVisitor=Gs,Fs.TriangleEdgesListVisitor=qs,Fs.TriangleVertexListVisitor=Bs,Fs.TriangleCoordinatesVisitor=zs,Fs.EDGE_COINCIDENCE_TOL_FACTOR=1e3,e(Vs.prototype,{getLineSegment:function(){return this.ls},getEndZ:function(){var t=this.ls.getCoordinate(1);return t.z},getStartZ:function(){var t=this.ls.getCoordinate(0);return t.z},intersection:function(t){return this.ls.intersection(t.getLineSegment())},getStart:function(){return this.ls.getCoordinate(0)},getEnd:function(){return this.ls.getCoordinate(1)},getEndY:function(){var t=this.ls.getCoordinate(1);return t.y},getStartX:function(){var t=this.ls.getCoordinate(0);return t.x},equalsTopo:function(t){return this.ls.equalsTopo(t.getLineSegment())},getStartY:function(){var t=this.ls.getCoordinate(0);return t.y},setData:function(t){this.data=t},getData:function(){return this.data},getEndX:function(){var t=this.ls.getCoordinate(1);return t.x},toString:function(){return this.ls.toString()},interfaces_:function(){return[]},getClass:function(){return Vs}}),e(ks.prototype,{visit:function(t){},interfaces_:function(){return[]},getClass:function(){return ks}}),e(Ys.prototype,{isRepeated:function(){return this.count>1},getRight:function(){return this.right},getCoordinate:function(){return this.p},setLeft:function(t){this.left=t},getX:function(){return this.p.x},getData:function(){return this.data},getCount:function(){return this.count},getLeft:function(){return this.left},getY:function(){return this.p.y},increment:function(){this.count=this.count+1},setRight:function(t){this.right=t},interfaces_:function(){return[]},getClass:function(){return Ys}}),e(Us.prototype,{insert:function(){if(1===arguments.length){var t=arguments[0];return this.insert(t,null)}if(2===arguments.length){var e=arguments[0],n=arguments[1];if(null===this.root)return this.root=new Ys(e,n),this.root;if(this.tolerance>0){var i=this.findBestMatchNode(e);if(null!==i)return i.increment(),i}return this.insertExact(e,n)}},query:function(){var t=arguments,e=this;if(1===arguments.length){var n=arguments[0],i=new I;return this.query(n,i),i}if(2===arguments.length)if(arguments[0]instanceof C&&R(arguments[1],y))!function(){var n=t[0],i=t[1];e.queryNode(e.root,n,!0,{interfaces_:function(){return[ks]},visit:function(t){i.add(t)}})}();else if(arguments[0]instanceof C&&R(arguments[1],ks)){var r=arguments[0],s=arguments[1];this.queryNode(this.root,r,!0,s)}},queryNode:function(t,e,n,i){if(null===t)return null;var r=null,s=null,o=null;n?(r=e.getMinX(),s=e.getMaxX(),o=t.getX()):(r=e.getMinY(),s=e.getMaxY(),o=t.getY());var a=o>r,u=s>=o;a&&this.queryNode(t.getLeft(),e,!n,i),e.contains(t.getCoordinate())&&i.visit(t),u&&this.queryNode(t.getRight(),e,!n,i)},findBestMatchNode:function(t){var e=new Xs(t,this.tolerance);return this.query(e.queryEnvelope(),e),e.getNode()},isEmpty:function(){return null===this.root},insertExact:function(t,e){for(var n=this.root,i=this.root,r=!0,s=!0;null!==n;){if(null!==n){var o=t.distance(n.getCoordinate())<=this.tolerance;if(o)return n.increment(),n}s=r?t.xa;a++)i.add(s.getCoordinate(),!0);return i.toCoordinateArray()}},e(Xs.prototype,{visit:function(t){var e=this.p.distance(t.getCoordinate()),n=e<=this.tolerance;if(!n)return null;var i=!1;(null===this.matchNode||e0&&td){var p=d;(null===u||l>p)&&(u=f,l=p)}}}return u},getConstraintSegments:function(){return this.segments},setSplitPointFinder:function(t){this.splitFinder=t},getConvexHull:function(){return this.convexHull},getTolerance:function(){return this.tolerance},enforceGabriel:function(t){for(var e=new I,n=0,i=new I,r=t.iterator();r.hasNext();){var s=r.next(),o=this.findNonGabrielPoint(s);if(null!==o){this.splitPt=this.splitFinder.findSplitPoint(s,o);var a=this.createVertex(this.splitPt,s),u=(this.insertSite(a),new Vs(s.getStartX(),s.getStartY(),s.getStartZ(),a.getX(),a.getY(),a.getZ(),s.getData())),l=new Vs(a.getX(),a.getY(),a.getZ(),s.getEndX(),s.getEndY(),s.getEndZ(),s.getData());e.add(u),e.add(l),i.add(s),n+=1}}return t.removeAll(i),t.addAll(e),n},createVertex:function(){if(1===arguments.length){var t=arguments[0],e=null;return e=null!==this.vertexFactory?this.vertexFactory.createVertex(t,null):new Ps(t)}if(2===arguments.length){var n=arguments[0],i=arguments[1],e=null;return e=null!==this.vertexFactory?this.vertexFactory.createVertex(n,i):new Ps(n),e.setOnConstraint(!0),e}},getSubdivision:function(){return this.subdiv},computeBoundingBox:function(){var t=Hs.computeVertexEnvelope(this.initialVertices),e=Hs.computeVertexEnvelope(this.segVertices),n=new C(t);n.expandToInclude(e);var i=.2*n.getWidth(),r=.2*n.getHeight(),s=Math.max(i,r);this.computeAreaEnv=new C(n),this.computeAreaEnv.expandBy(s)},setVertexFactory:function(t){this.vertexFactory=t},formInitialDelaunay:function(){this.computeBoundingBox(),this.subdiv=new Fs(this.computeAreaEnv,this.tolerance),this.subdiv.setLocator(new Ms(this.subdiv)),this.incDel=new Os(this.subdiv),this.insertSites(this.initialVertices)},insertSite:function(){if(arguments[0]instanceof Ps){var t=arguments[0],e=this.kdt.insert(t.getCoordinate(),t);if(e.isRepeated()){var n=e.getData();return n.merge(t),n}return this.incDel.insertSite(t),t}if(arguments[0]instanceof g){var i=arguments[0];this.insertSite(this.createVertex(i))}},interfaces_:function(){return[]},getClass:function(){return Hs}}),Hs.computeVertexEnvelope=function(t){for(var e=new C,n=t.iterator();n.hasNext();){var i=n.next();e.expandToInclude(i.getCoordinate())}return e},Hs.MAX_SPLIT_ITER=99,e(Ws.prototype,{create:function(){if(null!==this.subdiv)return null;var t=Ws.envelope(this.siteCoords),e=Ws.toVertices(this.siteCoords);this.subdiv=new Fs(t,this.tolerance);var n=new Os(this.subdiv);n.insertSites(e)},setTolerance:function(t){this.tolerance=t},setSites:function(){if(arguments[0]instanceof B){var t=arguments[0];this.siteCoords=Ws.extractUniqueCoordinates(t)}else if(R(arguments[0],v)){var e=arguments[0];this.siteCoords=Ws.unique(H.toCoordinateArray(e))}},getEdges:function(t){return this.create(),this.subdiv.getEdges(t)},getSubdivision:function(){return this.create(),this.subdiv},getTriangles:function(t){return this.create(),this.subdiv.getTriangles(t)},interfaces_:function(){return[]},getClass:function(){return Ws}}),Ws.extractUniqueCoordinates=function(t){if(null===t)return new N;var e=t.getCoordinates();return Ws.unique(e)},Ws.envelope=function(t){for(var e=new C,n=t.iterator();n.hasNext();){var i=n.next();e.expandToInclude(i)}return e},Ws.unique=function(t){var e=H.copyDeep(t);ut.sort(e);var n=new N(e,!1);return n},Ws.toVertices=function(t){for(var e=new I,n=t.iterator();n.hasNext();){var i=n.next();e.add(new Ts(i))}return e},e(js.prototype,{createSiteVertices:function(t){for(var e=new I,n=t.iterator();n.hasNext();){var i=n.next();this.constraintVertexMap.containsKey(i)||e.add(new Ps(i))}return e},create:function(){if(null!==this.subdiv)return null;var t=Ws.envelope(this.siteCoords),e=new I;null!==this.constraintLines&&(t.expandToInclude(this.constraintLines.getEnvelopeInternal()),this.createVertices(this.constraintLines),e=js.createConstraintSegments(this.constraintLines));var n=this.createSiteVertices(this.siteCoords),i=new Hs(n,this.tolerance);i.setConstraints(e,new I(this.constraintVertexMap.values())),i.formInitialDelaunay(),i.enforceConstraints(),this.subdiv=i.getSubdivision()},setTolerance:function(t){this.tolerance=t},setConstraints:function(t){this.constraintLines=t},setSites:function(t){this.siteCoords=Ws.extractUniqueCoordinates(t)},getEdges:function(t){return this.create(),this.subdiv.getEdges(t)},getSubdivision:function(){return this.create(),this.subdiv},getTriangles:function(t){return this.create(),this.subdiv.getTriangles(t)},createVertices:function(t){for(var e=t.getCoordinates(),n=0;nn;n++)e[n]=arguments[n];return Jr.relate.apply(Jr,[this].concat(e))},getCentroid:function(){if(this.isEmpty())return this.factory.createPoint();var t=ge.getCentroid(this);return this.createPointFromInternalCoord(t,this)},getInteriorPoint:function(){if(this.isEmpty())return this.factory.createPoint();var t=null,e=this.getDimension();if(0===e){var n=new li(this);t=n.getInteriorPoint()}else if(1===e){var n=new ui(this);t=n.getInteriorPoint()}else{var n=new oi(this);t=n.getInteriorPoint()}return this.createPointFromInternalCoord(t,this)},symDifference:function(t){if(this.isEmpty()||t.isEmpty()){if(this.isEmpty()&&t.isEmpty())return ii.createEmptyResult(ii.SYMDIFFERENCE,this,t,this.factory);if(this.isEmpty())return t.copy();if(t.isEmpty())return this.copy()}return this.checkNotGeometryCollection(this),this.checkNotGeometryCollection(t),si.overlayOp(this,t,ii.SYMDIFFERENCE)},createPointFromInternalCoord:function(t,e){return e.getPrecisionModel().makePrecise(t),e.getFactory().createPoint(t)},toText:function(){var t=new se;return t.write(this)},toString:function(){this.toText()},contains:function(t){return Jr.contains(this,t)},difference:function(t){return this.isEmpty()?ii.createEmptyResult(ii.DIFFERENCE,this,t,this.factory):t.isEmpty()?this.copy():(this.checkNotGeometryCollection(this),this.checkNotGeometryCollection(t),si.overlayOp(this,t,ii.DIFFERENCE))},isSimple:function(){var t=new Wi(this);return t.isSimple()},isWithinDistance:function(t,e){var n=this.getEnvelopeInternal().distance(t.getEnvelopeInternal());return n>e?!1:xr.isWithinDistance(this,t,e)},distance:function(t){return xr.distance(this,t)},isEquivalentClass:function(t){return this.getClass()===t.getClass()}});var Fo="1.2.0 (d405c89)";t.version=Fo,t.algorithm=co,t.densify=fo,t.dissolve=go,t.geom=lo,t.geomgraph=po,t.index=yo,t.io=No,t.noding=Co,t.operation=_o,t.precision=Mo,t.simplify=Do,t.triangulate=Ao}); + +},{}],9:[function(require,module,exports){ - if (i !== len) { - x = a[i] - y = b[i] - } +},{}],10:[function(require,module,exports){ +// (c) Dean McNamee , 2012. +// +// https://github.com/deanm/css-color-parser-js +// +// 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. - 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 'binary': - case 'base64': - case 'raw': - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return true - default: - return false - } +// http://www.w3.org/TR/css3-color/ +var kCSSColorTable = { + "transparent": [0,0,0,0], "aliceblue": [240,248,255,1], + "antiquewhite": [250,235,215,1], "aqua": [0,255,255,1], + "aquamarine": [127,255,212,1], "azure": [240,255,255,1], + "beige": [245,245,220,1], "bisque": [255,228,196,1], + "black": [0,0,0,1], "blanchedalmond": [255,235,205,1], + "blue": [0,0,255,1], "blueviolet": [138,43,226,1], + "brown": [165,42,42,1], "burlywood": [222,184,135,1], + "cadetblue": [95,158,160,1], "chartreuse": [127,255,0,1], + "chocolate": [210,105,30,1], "coral": [255,127,80,1], + "cornflowerblue": [100,149,237,1], "cornsilk": [255,248,220,1], + "crimson": [220,20,60,1], "cyan": [0,255,255,1], + "darkblue": [0,0,139,1], "darkcyan": [0,139,139,1], + "darkgoldenrod": [184,134,11,1], "darkgray": [169,169,169,1], + "darkgreen": [0,100,0,1], "darkgrey": [169,169,169,1], + "darkkhaki": [189,183,107,1], "darkmagenta": [139,0,139,1], + "darkolivegreen": [85,107,47,1], "darkorange": [255,140,0,1], + "darkorchid": [153,50,204,1], "darkred": [139,0,0,1], + "darksalmon": [233,150,122,1], "darkseagreen": [143,188,143,1], + "darkslateblue": [72,61,139,1], "darkslategray": [47,79,79,1], + "darkslategrey": [47,79,79,1], "darkturquoise": [0,206,209,1], + "darkviolet": [148,0,211,1], "deeppink": [255,20,147,1], + "deepskyblue": [0,191,255,1], "dimgray": [105,105,105,1], + "dimgrey": [105,105,105,1], "dodgerblue": [30,144,255,1], + "firebrick": [178,34,34,1], "floralwhite": [255,250,240,1], + "forestgreen": [34,139,34,1], "fuchsia": [255,0,255,1], + "gainsboro": [220,220,220,1], "ghostwhite": [248,248,255,1], + "gold": [255,215,0,1], "goldenrod": [218,165,32,1], + "gray": [128,128,128,1], "green": [0,128,0,1], + "greenyellow": [173,255,47,1], "grey": [128,128,128,1], + "honeydew": [240,255,240,1], "hotpink": [255,105,180,1], + "indianred": [205,92,92,1], "indigo": [75,0,130,1], + "ivory": [255,255,240,1], "khaki": [240,230,140,1], + "lavender": [230,230,250,1], "lavenderblush": [255,240,245,1], + "lawngreen": [124,252,0,1], "lemonchiffon": [255,250,205,1], + "lightblue": [173,216,230,1], "lightcoral": [240,128,128,1], + "lightcyan": [224,255,255,1], "lightgoldenrodyellow": [250,250,210,1], + "lightgray": [211,211,211,1], "lightgreen": [144,238,144,1], + "lightgrey": [211,211,211,1], "lightpink": [255,182,193,1], + "lightsalmon": [255,160,122,1], "lightseagreen": [32,178,170,1], + "lightskyblue": [135,206,250,1], "lightslategray": [119,136,153,1], + "lightslategrey": [119,136,153,1], "lightsteelblue": [176,196,222,1], + "lightyellow": [255,255,224,1], "lime": [0,255,0,1], + "limegreen": [50,205,50,1], "linen": [250,240,230,1], + "magenta": [255,0,255,1], "maroon": [128,0,0,1], + "mediumaquamarine": [102,205,170,1], "mediumblue": [0,0,205,1], + "mediumorchid": [186,85,211,1], "mediumpurple": [147,112,219,1], + "mediumseagreen": [60,179,113,1], "mediumslateblue": [123,104,238,1], + "mediumspringgreen": [0,250,154,1], "mediumturquoise": [72,209,204,1], + "mediumvioletred": [199,21,133,1], "midnightblue": [25,25,112,1], + "mintcream": [245,255,250,1], "mistyrose": [255,228,225,1], + "moccasin": [255,228,181,1], "navajowhite": [255,222,173,1], + "navy": [0,0,128,1], "oldlace": [253,245,230,1], + "olive": [128,128,0,1], "olivedrab": [107,142,35,1], + "orange": [255,165,0,1], "orangered": [255,69,0,1], + "orchid": [218,112,214,1], "palegoldenrod": [238,232,170,1], + "palegreen": [152,251,152,1], "paleturquoise": [175,238,238,1], + "palevioletred": [219,112,147,1], "papayawhip": [255,239,213,1], + "peachpuff": [255,218,185,1], "peru": [205,133,63,1], + "pink": [255,192,203,1], "plum": [221,160,221,1], + "powderblue": [176,224,230,1], "purple": [128,0,128,1], + "rebeccapurple": [102,51,153,1], + "red": [255,0,0,1], "rosybrown": [188,143,143,1], + "royalblue": [65,105,225,1], "saddlebrown": [139,69,19,1], + "salmon": [250,128,114,1], "sandybrown": [244,164,96,1], + "seagreen": [46,139,87,1], "seashell": [255,245,238,1], + "sienna": [160,82,45,1], "silver": [192,192,192,1], + "skyblue": [135,206,235,1], "slateblue": [106,90,205,1], + "slategray": [112,128,144,1], "slategrey": [112,128,144,1], + "snow": [255,250,250,1], "springgreen": [0,255,127,1], + "steelblue": [70,130,180,1], "tan": [210,180,140,1], + "teal": [0,128,128,1], "thistle": [216,191,216,1], + "tomato": [255,99,71,1], "turquoise": [64,224,208,1], + "violet": [238,130,238,1], "wheat": [245,222,179,1], + "white": [255,255,255,1], "whitesmoke": [245,245,245,1], + "yellow": [255,255,0,1], "yellowgreen": [154,205,50,1]} + +function clamp_css_byte(i) { // Clamp to integer 0 .. 255. + i = Math.round(i); // Seems to be what Chrome does (vs truncation). + return i < 0 ? 0 : i > 255 ? 255 : i; +} + +function clamp_css_float(f) { // Clamp to float 0.0 .. 1.0. + return f < 0 ? 0 : f > 1 ? 1 : f; } -Buffer.concat = function concat (list, length) { - if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.') +function parse_css_int(str) { // int or percentage. + if (str[str.length - 1] === '%') + return clamp_css_byte(parseFloat(str) / 100 * 255); + return clamp_css_byte(parseInt(str)); +} - if (list.length === 0) { - return new Buffer(0) - } +function parse_css_float(str) { // float or percentage. + if (str[str.length - 1] === '%') + return clamp_css_float(parseFloat(str) / 100); + return clamp_css_float(parseFloat(str)); +} + +function css_hue_to_rgb(m1, m2, h) { + if (h < 0) h += 1; + else if (h > 1) h -= 1; + + if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; + if (h * 2 < 1) return m2; + if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; + return m1; +} + +function parseCSSColor(css_str) { + // Remove all whitespace, not compliant, but should just be more accepting. + var str = css_str.replace(/ /g, '').toLowerCase(); + + // Color keywords (and transparent) lookup. + if (str in kCSSColorTable) return kCSSColorTable[str].slice(); // dup. - var i - if (length === undefined) { - length = 0 - for (i = 0; i < list.length; i++) { - length += list[i].length + // #abc and #abc123 syntax. + if (str[0] === '#') { + if (str.length === 4) { + var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. + if (!(iv >= 0 && iv <= 0xfff)) return null; // Covers NaN. + return [((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8), + (iv & 0xf0) | ((iv & 0xf0) >> 4), + (iv & 0xf) | ((iv & 0xf) << 4), + 1]; + } else if (str.length === 7) { + var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. + if (!(iv >= 0 && iv <= 0xffffff)) return null; // Covers NaN. + return [(iv & 0xff0000) >> 16, + (iv & 0xff00) >> 8, + iv & 0xff, + 1]; } - } - var buf = new Buffer(length) - var pos = 0 - for (i = 0; i < list.length; i++) { - var item = list[i] - item.copy(buf, pos) - pos += item.length + return null; } - return buf -} - -function byteLength (string, encoding) { - if (typeof string !== 'string') string = '' + string - - var len = string.length - if (len === 0) return 0 - - // Use a for loop to avoid recursion - var loweredCase = false - for (;;) { - switch (encoding) { - case 'ascii': - case 'binary': - // Deprecated - case 'raw': - case 'raws': - 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 + + var op = str.indexOf('('), ep = str.indexOf(')'); + if (op !== -1 && ep + 1 === str.length) { + var fname = str.substr(0, op); + var params = str.substr(op+1, ep-(op+1)).split(','); + var alpha = 1; // To allow case fallthrough. + switch (fname) { + case 'rgba': + if (params.length !== 4) return null; + alpha = parse_css_float(params.pop()); + // Fall through. + case 'rgb': + if (params.length !== 3) return null; + return [parse_css_int(params[0]), + parse_css_int(params[1]), + parse_css_int(params[2]), + alpha]; + case 'hsla': + if (params.length !== 4) return null; + alpha = parse_css_float(params.pop()); + // Fall through. + case 'hsl': + if (params.length !== 3) return null; + var h = (((parseFloat(params[0]) % 360) + 360) % 360) / 360; // 0 .. 1 + // NOTE(deanm): According to the CSS spec s/l should only be + // percentages, but we don't bother and let float or percentage. + var s = parse_css_float(params[1]); + var l = parse_css_float(params[2]); + var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; + var m1 = l * 2 - m2; + return [clamp_css_byte(css_hue_to_rgb(m1, m2, h+1/3) * 255), + clamp_css_byte(css_hue_to_rgb(m1, m2, h) * 255), + clamp_css_byte(css_hue_to_rgb(m1, m2, h-1/3) * 255), + alpha]; default: - if (loweredCase) return utf8ToBytes(string).length // assume utf8 - encoding = ('' + encoding).toLowerCase() - loweredCase = true + return null; } } + + return null; } -Buffer.byteLength = byteLength -function slowToString (encoding, start, end) { - var loweredCase = false +try { exports.parseCSSColor = parseCSSColor } catch(e) { } - start = start | 0 - end = end === undefined || end === Infinity ? this.length : end | 0 +},{}],11:[function(require,module,exports){ +'use strict'; - if (!encoding) encoding = 'utf8' - if (start < 0) start = 0 - if (end > this.length) end = this.length - if (end <= start) return '' +module.exports = earcut; - while (true) { - switch (encoding) { - case 'hex': - return hexSlice(this, start, end) +function earcut(data, holeIndices, dim) { - case 'utf8': - case 'utf-8': - return utf8Slice(this, start, end) + dim = dim || 2; - case 'ascii': - return asciiSlice(this, start, end) + var hasHoles = holeIndices && holeIndices.length, + outerLen = hasHoles ? holeIndices[0] * dim : data.length, + outerNode = linkedList(data, 0, outerLen, dim, true), + triangles = []; - case 'binary': - return binarySlice(this, start, end) + if (!outerNode) return triangles; - case 'base64': - return base64Slice(this, start, end) + var minX, minY, maxX, maxY, x, y, size; - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return utf16leSlice(this, start, end) + if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim); - default: - if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) - encoding = (encoding + '').toLowerCase() - loweredCase = true - } - } -} + // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox + if (data.length > 80 * dim) { + minX = maxX = data[0]; + minY = maxY = data[1]; -// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect -// Buffer instances. -Buffer.prototype._isBuffer = true - -Buffer.prototype.toString = function toString () { - var length = this.length | 0 - if (length === 0) return '' - if (arguments.length === 0) return utf8Slice(this, 0, length) - return slowToString.apply(this, arguments) -} + for (var i = dim; i < outerLen; i += dim) { + x = data[i]; + y = data[i + 1]; + if (x < minX) minX = x; + if (y < minY) minY = y; + if (x > maxX) maxX = x; + if (y > maxY) maxY = y; + } -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 -} + // minX, minY and size are later used to transform coords into integers for z-order calculation + size = Math.max(maxX - minX, maxY - minY); + } -Buffer.prototype.inspect = function inspect () { - var str = '' - var max = exports.INSPECT_MAX_BYTES - if (this.length > 0) { - str = this.toString('hex', 0, max).match(/.{2}/g).join(' ') - if (this.length > max) str += ' ... ' - } - return '' -} + earcutLinked(outerNode, triangles, dim, minX, minY, size); -Buffer.prototype.compare = function compare (b) { - if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') - if (this === b) return 0 - return Buffer.compare(this, b) + return triangles; } -Buffer.prototype.indexOf = function indexOf (val, byteOffset) { - if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff - else if (byteOffset < -0x80000000) byteOffset = -0x80000000 - byteOffset >>= 0 - - if (this.length === 0) return -1 - if (byteOffset >= this.length) return -1 +// create a circular doubly linked list from polygon points in the specified winding order +function linkedList(data, start, end, dim, clockwise) { + var i, last; - // Negative offsets start from the end of the buffer - if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0) - - if (typeof val === 'string') { - if (val.length === 0) return -1 // special case: looking for empty string always fails - return String.prototype.indexOf.call(this, val, byteOffset) - } - if (Buffer.isBuffer(val)) { - return arrayIndexOf(this, val, byteOffset) - } - if (typeof val === 'number') { - if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') { - return Uint8Array.prototype.indexOf.call(this, val, byteOffset) + if (clockwise === (signedArea(data, start, end, dim) > 0)) { + for (i = start; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last); + } else { + for (i = end - dim; i >= start; i -= dim) last = insertNode(i, data[i], data[i + 1], last); } - return arrayIndexOf(this, [ val ], byteOffset) - } - function arrayIndexOf (arr, val, byteOffset) { - var foundIndex = -1 - for (var i = 0; byteOffset + i < arr.length; i++) { - if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) { - if (foundIndex === -1) foundIndex = i - if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex - } else { - foundIndex = -1 - } + if (last && equals(last, last.next)) { + removeNode(last); + last = last.next; } - return -1 - } - throw new TypeError('val must be string, number or Buffer') + return last; } -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 - } - } - - // must be an even number of digits - var strLen = string.length - if (strLen % 2 !== 0) throw new Error('Invalid hex string') +// eliminate colinear or duplicate points +function filterPoints(start, end) { + if (!start) return start; + if (!end) end = start; - if (length > strLen / 2) { - length = strLen / 2 - } - for (var i = 0; i < length; i++) { - var parsed = parseInt(string.substr(i * 2, 2), 16) - if (isNaN(parsed)) throw new Error('Invalid hex string') - buf[offset + i] = parsed - } - return i -} + var p = start, + again; + do { + again = false; -function utf8Write (buf, string, offset, length) { - return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) -} + if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) { + removeNode(p); + p = end = p.prev; + if (p === p.next) return null; + again = true; -function asciiWrite (buf, string, offset, length) { - return blitBuffer(asciiToBytes(string), buf, offset, length) -} + } else { + p = p.next; + } + } while (again || p !== end); -function binaryWrite (buf, string, offset, length) { - return asciiWrite(buf, string, offset, length) + return end; } -function base64Write (buf, string, offset, length) { - return blitBuffer(base64ToBytes(string), buf, offset, length) -} +// main ear slicing loop which triangulates a polygon (given as a linked list) +function earcutLinked(ear, triangles, dim, minX, minY, size, pass) { + if (!ear) return; -function ucs2Write (buf, string, offset, length) { - return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) -} + // interlink polygon nodes in z-order + if (!pass && size) indexCurve(ear, minX, minY, size); -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 - } - // legacy write(string, encoding, offset, length) - remove in v0.13 - } else { - var swap = encoding - encoding = offset - offset = length | 0 - length = swap - } + var stop = ear, + prev, next; - var remaining = this.length - offset - if (length === undefined || length > remaining) length = remaining + // iterate through ears, slicing them one by one + while (ear.prev !== ear.next) { + prev = ear.prev; + next = ear.next; - if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { - throw new RangeError('attempt to write outside buffer bounds') - } + if (size ? isEarHashed(ear, minX, minY, size) : isEar(ear)) { + // cut off the triangle + triangles.push(prev.i / dim); + triangles.push(ear.i / dim); + triangles.push(next.i / dim); - if (!encoding) encoding = 'utf8' + removeNode(ear); - var loweredCase = false - for (;;) { - switch (encoding) { - case 'hex': - return hexWrite(this, string, offset, length) + // skipping the next vertice leads to less sliver triangles + ear = next.next; + stop = next.next; - case 'utf8': - case 'utf-8': - return utf8Write(this, string, offset, length) + continue; + } - case 'ascii': - return asciiWrite(this, string, offset, length) + ear = next; - case 'binary': - return binaryWrite(this, string, offset, length) + // if we looped through the whole remaining polygon and can't find any more ears + if (ear === stop) { + // try filtering points and slicing again + if (!pass) { + earcutLinked(filterPoints(ear), triangles, dim, minX, minY, size, 1); - case 'base64': - // Warning: maxLength not taken into account in base64Write - return base64Write(this, string, offset, length) + // if this didn't work, try curing all small self-intersections locally + } else if (pass === 1) { + ear = cureLocalIntersections(ear, triangles, dim); + earcutLinked(ear, triangles, dim, minX, minY, size, 2); - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return ucs2Write(this, string, offset, length) + // as a last resort, try splitting the remaining polygon into two + } else if (pass === 2) { + splitEarcut(ear, triangles, dim, minX, minY, size); + } - default: - if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) - encoding = ('' + encoding).toLowerCase() - loweredCase = true + break; + } } - } } -Buffer.prototype.toJSON = function toJSON () { - return { - type: 'Buffer', - data: Array.prototype.slice.call(this._arr || this, 0) - } -} +// check whether a polygon node forms a valid ear with adjacent nodes +function isEar(ear) { + var a = ear.prev, + b = ear, + c = ear.next; -function base64Slice (buf, start, end) { - if (start === 0 && end === buf.length) { - return base64.fromByteArray(buf) - } else { - return base64.fromByteArray(buf.slice(start, end)) - } -} + if (area(a, b, c) >= 0) return false; // reflex, can't be an ear -function utf8Slice (buf, start, end) { - end = Math.min(buf.length, end) - var res = [] + // now make sure we don't have other points inside the potential ear + var p = ear.next.next; - 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 + while (p !== ear.prev) { + if (pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && + area(p.prev, p, p.next) >= 0) return false; + p = p.next; + } - if (i + bytesPerSequence <= end) { - var secondByte, thirdByte, fourthByte, tempCodePoint + return true; +} - 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 - } - } - } - } +function isEarHashed(ear, minX, minY, size) { + var a = ear.prev, + b = ear, + c = ear.next; - 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 - } + if (area(a, b, c) >= 0) return false; // reflex, can't be an ear - res.push(codePoint) - i += bytesPerSequence - } + // triangle bbox; min & max are calculated like this for speed + var minTX = a.x < b.x ? (a.x < c.x ? a.x : c.x) : (b.x < c.x ? b.x : c.x), + minTY = a.y < b.y ? (a.y < c.y ? a.y : c.y) : (b.y < c.y ? b.y : c.y), + maxTX = a.x > b.x ? (a.x > c.x ? a.x : c.x) : (b.x > c.x ? b.x : c.x), + maxTY = a.y > b.y ? (a.y > c.y ? a.y : c.y) : (b.y > c.y ? b.y : c.y); - return decodeCodePointsArray(res) -} + // z-order range for the current triangle bbox; + var minZ = zOrder(minTX, minTY, minX, minY, size), + maxZ = zOrder(maxTX, maxTY, minX, minY, size); -// 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 + // first look for points inside the triangle in increasing z-order + var p = ear.nextZ; -function decodeCodePointsArray (codePoints) { - var len = codePoints.length - if (len <= MAX_ARGUMENTS_LENGTH) { - return String.fromCharCode.apply(String, codePoints) // avoid extra slice() - } + while (p && p.z <= maxZ) { + if (p !== ear.prev && p !== ear.next && + pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && + area(p.prev, p, p.next) >= 0) return false; + p = p.nextZ; + } - // 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 -} + // then look for points in decreasing z-order + p = ear.prevZ; -function asciiSlice (buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) + while (p && p.z >= minZ) { + if (p !== ear.prev && p !== ear.next && + pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && + area(p.prev, p, p.next) >= 0) return false; + p = p.prevZ; + } - for (var i = start; i < end; i++) { - ret += String.fromCharCode(buf[i] & 0x7F) - } - return ret + return true; } -function binarySlice (buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) +// go through all polygon nodes and cure small local self-intersections +function cureLocalIntersections(start, triangles, dim) { + var p = start; + do { + var a = p.prev, + b = p.next.next; - for (var i = start; i < end; i++) { - ret += String.fromCharCode(buf[i]) - } - return ret -} + if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) { -function hexSlice (buf, start, end) { - var len = buf.length + triangles.push(a.i / dim); + triangles.push(p.i / dim); + triangles.push(b.i / dim); - if (!start || start < 0) start = 0 - if (!end || end < 0 || end > len) end = len + // remove two nodes involved + removeNode(p); + removeNode(p.next); - var out = '' - for (var i = start; i < end; i++) { - out += toHex(buf[i]) - } - return out -} + p = start = b; + } + p = p.next; + } while (p !== start); -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 + return p; } -Buffer.prototype.slice = function slice (start, end) { - var len = this.length - start = ~~start - end = end === undefined ? len : ~~end +// try splitting polygon into two and triangulate them independently +function splitEarcut(start, triangles, dim, minX, minY, size) { + // look for a valid diagonal that divides the polygon into two + var a = start; + do { + var b = a.next.next; + while (b !== a.prev) { + if (a.i !== b.i && isValidDiagonal(a, b)) { + // split the polygon in two by the diagonal + var c = splitPolygon(a, b); + + // filter colinear points around the cuts + a = filterPoints(a, a.next); + c = filterPoints(c, c.next); + + // run earcut on each half + earcutLinked(a, triangles, dim, minX, minY, size); + earcutLinked(c, triangles, dim, minX, minY, size); + return; + } + b = b.next; + } + a = a.next; + } while (a !== start); +} - if (start < 0) { - start += len - if (start < 0) start = 0 - } else if (start > len) { - start = len - } +// link every hole into the outer loop, producing a single-ring polygon without holes +function eliminateHoles(data, holeIndices, outerNode, dim) { + var queue = [], + i, len, start, end, list; - if (end < 0) { - end += len - if (end < 0) end = 0 - } else if (end > len) { - end = len - } + for (i = 0, len = holeIndices.length; i < len; i++) { + start = holeIndices[i] * dim; + end = i < len - 1 ? holeIndices[i + 1] * dim : data.length; + list = linkedList(data, start, end, dim, false); + if (list === list.next) list.steiner = true; + queue.push(getLeftmost(list)); + } - if (end < start) end = start + queue.sort(compareX); - var newBuf - if (Buffer.TYPED_ARRAY_SUPPORT) { - newBuf = this.subarray(start, end) - newBuf.__proto__ = Buffer.prototype - } else { - var sliceLen = end - start - newBuf = new Buffer(sliceLen, undefined) - for (var i = 0; i < sliceLen; i++) { - newBuf[i] = this[i + start] + // process holes from left to right + for (i = 0; i < queue.length; i++) { + eliminateHole(queue[i], outerNode); + outerNode = filterPoints(outerNode, outerNode.next); } - } - if (newBuf.length) newBuf.parent = this.parent || this + return outerNode; +} - return newBuf +function compareX(a, b) { + return a.x - b.x; } -/* - * 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') +// find a bridge between vertices that connects hole with an outer ring and and link it +function eliminateHole(hole, outerNode) { + outerNode = findHoleBridge(hole, outerNode); + if (outerNode) { + var b = splitPolygon(outerNode, hole); + filterPoints(b, b.next); + } } -Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) +// David Eberly's algorithm for finding a bridge between hole and outer polygon +function findHoleBridge(hole, outerNode) { + var p = outerNode, + hx = hole.x, + hy = hole.y, + qx = -Infinity, + m; - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } + // find a segment intersected by a ray from the hole's leftmost point to the left; + // segment's endpoint with lesser x will be potential connection point + do { + if (hy <= p.y && hy >= p.next.y) { + var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y); + if (x <= hx && x > qx) { + qx = x; + if (x === hx) { + if (hy === p.y) return p; + if (hy === p.next.y) return p.next; + } + m = p.x < p.next.x ? p : p.next; + } + } + p = p.next; + } while (p !== outerNode); - return val -} + if (!m) return null; -Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - checkOffset(offset, byteLength, this.length) - } + if (hx === qx) return m.prev; // hole touches outer segment; pick lower endpoint - var val = this[offset + --byteLength] - var mul = 1 - while (byteLength > 0 && (mul *= 0x100)) { - val += this[offset + --byteLength] * mul - } + // look for points inside the triangle of hole point, segment intersection and endpoint; + // if there are no points found, we have a valid connection; + // otherwise choose the point of the minimum angle with the ray as connection point - return val -} + var stop = m, + mx = m.x, + my = m.y, + tanMin = Infinity, + tan; -Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { - if (!noAssert) checkOffset(offset, 1, this.length) - return this[offset] -} + p = m.next; -Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - return this[offset] | (this[offset + 1] << 8) -} + while (p !== stop) { + if (hx >= p.x && p.x >= mx && + pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) { -Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - return (this[offset] << 8) | this[offset + 1] -} + tan = Math.abs(hy - p.y) / (hx - p.x); // tangential -Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) + if ((tan < tanMin || (tan === tanMin && p.x > m.x)) && locallyInside(p, hole)) { + m = p; + tanMin = tan; + } + } + + p = p.next; + } - return ((this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16)) + - (this[offset + 3] * 0x1000000) + return m; } -Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) +// interlink polygon nodes in z-order +function indexCurve(start, minX, minY, size) { + var p = start; + do { + if (p.z === null) p.z = zOrder(p.x, p.y, minX, minY, size); + p.prevZ = p.prev; + p.nextZ = p.next; + p = p.next; + } while (p !== start); + + p.prevZ.nextZ = null; + p.prevZ = null; - return (this[offset] * 0x1000000) + - ((this[offset + 1] << 16) | - (this[offset + 2] << 8) | - this[offset + 3]) + sortLinked(p); } -Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) +// Simon Tatham's linked list merge sort algorithm +// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html +function sortLinked(list) { + var i, p, q, e, tail, numMerges, pSize, qSize, + inSize = 1; - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } - mul *= 0x80 + do { + p = list; + list = null; + tail = null; + numMerges = 0; + + while (p) { + numMerges++; + q = p; + pSize = 0; + for (i = 0; i < inSize; i++) { + pSize++; + q = q.nextZ; + if (!q) break; + } - if (val >= mul) val -= Math.pow(2, 8 * byteLength) + qSize = inSize; + + while (pSize > 0 || (qSize > 0 && q)) { + + if (pSize === 0) { + e = q; + q = q.nextZ; + qSize--; + } else if (qSize === 0 || !q) { + e = p; + p = p.nextZ; + pSize--; + } else if (p.z <= q.z) { + e = p; + p = p.nextZ; + pSize--; + } else { + e = q; + q = q.nextZ; + qSize--; + } - return val -} + if (tail) tail.nextZ = e; + else list = e; -Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) + e.prevZ = tail; + tail = e; + } - var i = byteLength - var mul = 1 - var val = this[offset + --i] - while (i > 0 && (mul *= 0x100)) { - val += this[offset + --i] * mul - } - mul *= 0x80 + p = q; + } - if (val >= mul) val -= Math.pow(2, 8 * byteLength) + tail.nextZ = null; + inSize *= 2; - return val -} + } while (numMerges > 1); -Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { - if (!noAssert) checkOffset(offset, 1, this.length) - if (!(this[offset] & 0x80)) return (this[offset]) - return ((0xff - this[offset] + 1) * -1) + return list; } -Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - var val = this[offset] | (this[offset + 1] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val -} +// z-order of a point given coords and size of the data bounding box +function zOrder(x, y, minX, minY, size) { + // coords are transformed into non-negative 15-bit integer range + x = 32767 * (x - minX) / size; + y = 32767 * (y - minY) / size; -Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - var val = this[offset + 1] | (this[offset] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val -} + x = (x | (x << 8)) & 0x00FF00FF; + x = (x | (x << 4)) & 0x0F0F0F0F; + x = (x | (x << 2)) & 0x33333333; + x = (x | (x << 1)) & 0x55555555; -Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) + y = (y | (y << 8)) & 0x00FF00FF; + y = (y | (y << 4)) & 0x0F0F0F0F; + y = (y | (y << 2)) & 0x33333333; + y = (y | (y << 1)) & 0x55555555; - return (this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16) | - (this[offset + 3] << 24) + return x | (y << 1); } -Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) +// find the leftmost node of a polygon ring +function getLeftmost(start) { + var p = start, + leftmost = start; + do { + if (p.x < leftmost.x) leftmost = p; + p = p.next; + } while (p !== start); - return (this[offset] << 24) | - (this[offset + 1] << 16) | - (this[offset + 2] << 8) | - (this[offset + 3]) + return leftmost; } -Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - return ieee754.read(this, offset, true, 23, 4) +// check if a point lies within a convex triangle +function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) { + return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 && + (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 && + (bx - px) * (cy - py) - (cx - px) * (by - py) >= 0; } -Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - return ieee754.read(this, offset, false, 23, 4) +// check if a diagonal between two polygon nodes is valid (lies in polygon interior) +function isValidDiagonal(a, b) { + return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && + locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b); } -Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 8, this.length) - return ieee754.read(this, offset, true, 52, 8) +// signed area of a triangle +function area(p, q, r) { + return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); } -Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 8, this.length) - return ieee754.read(this, offset, false, 52, 8) +// check if two points are equal +function equals(p1, p2) { + return p1.x === p2.x && p1.y === p2.y; } -function checkInt (buf, value, offset, ext, max, min) { - if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance') - if (value > max || value < min) throw new RangeError('value is out of bounds') - if (offset + ext > buf.length) throw new RangeError('index out of range') +// check if two segments intersect +function intersects(p1, q1, p2, q2) { + if ((equals(p1, q1) && equals(p2, q2)) || + (equals(p1, q2) && equals(p2, q1))) return true; + return area(p1, q1, p2) > 0 !== area(p1, q1, q2) > 0 && + area(p2, q2, p1) > 0 !== area(p2, q2, q1) > 0; } -Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0) - - var mul = 1 - var i = 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } +// check if a polygon diagonal intersects any polygon segments +function intersectsPolygon(a, b) { + var p = a; + do { + if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && + intersects(p, p.next, a, b)) return true; + p = p.next; + } while (p !== a); - return offset + byteLength + return false; } -Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0) +// check if a polygon diagonal is locally inside the polygon +function locallyInside(a, b) { + return area(a.prev, a, a.next) < 0 ? + area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 : + area(a, b, a.prev) < 0 || area(a, a.next, b) < 0; +} - var i = byteLength - 1 - var mul = 1 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } +// check if the middle point of a polygon diagonal is inside the polygon +function middleInside(a, b) { + var p = a, + inside = false, + px = (a.x + b.x) / 2, + py = (a.y + b.y) / 2; + do { + if (((p.y > py) !== (p.next.y > py)) && (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x)) + inside = !inside; + p = p.next; + } while (p !== a); - return offset + byteLength + return inside; } -Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) - this[offset] = (value & 0xff) - return offset + 1 -} +// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two; +// if one belongs to the outer ring and another to a hole, it merges it into a single ring +function splitPolygon(a, b) { + var a2 = new Node(a.i, a.x, a.y), + b2 = new Node(b.i, b.x, b.y), + an = a.next, + bp = b.prev; -function objectWriteUInt16 (buf, value, offset, littleEndian) { - if (value < 0) value = 0xffff + value + 1 - for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) { - buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> - (littleEndian ? i : 1 - i) * 8 - } -} + a.next = b; + b.prev = a; -Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } - return offset + 2 -} + a2.next = an; + an.prev = a2; -Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - } else { - objectWriteUInt16(this, value, offset, false) - } - return offset + 2 + b2.next = a2; + a2.prev = b2; + + bp.next = b2; + b2.prev = bp; + + return b2; } -function objectWriteUInt32 (buf, value, offset, littleEndian) { - if (value < 0) value = 0xffffffff + value + 1 - for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) { - buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff - } +// create a node and optionally link it with previous one (in a circular doubly linked list) +function insertNode(i, x, y, last) { + var p = new Node(i, x, y); + + if (!last) { + p.prev = p; + p.next = p; + + } else { + p.next = last.next; + p.prev = last; + last.next.prev = p; + last.next = p; + } + return p; } -Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset + 3] = (value >>> 24) - this[offset + 2] = (value >>> 16) - this[offset + 1] = (value >>> 8) - this[offset] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, true) - } - 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) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, false) - } - return offset + 4 +function removeNode(p) { + p.next.prev = p.prev; + p.prev.next = p.next; + + if (p.prevZ) p.prevZ.nextZ = p.nextZ; + if (p.nextZ) p.nextZ.prevZ = p.prevZ; } -Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) +function Node(i, x, y) { + // vertice index in coordinates array + this.i = i; - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } + // vertex coordinates + this.x = x; + this.y = y; - var i = 0 - var mul = 1 - var sub = value < 0 ? 1 : 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } + // previous and next vertice nodes in a polygon ring + this.prev = null; + this.next = null; + + // z-order curve value + this.z = null; - return offset + byteLength + // previous and next nodes in z-order + this.prevZ = null; + this.nextZ = null; + + // indicates whether this is a steiner point + this.steiner = false; } -Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) +// return a percentage difference between the polygon area and its triangulation area; +// used to verify correctness of triangulation +earcut.deviation = function (data, holeIndices, dim, triangles) { + var hasHoles = holeIndices && holeIndices.length; + var outerLen = hasHoles ? holeIndices[0] * dim : data.length; - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } + var polygonArea = Math.abs(signedArea(data, 0, outerLen, dim)); + if (hasHoles) { + for (var i = 0, len = holeIndices.length; i < len; i++) { + var start = holeIndices[i] * dim; + var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length; + polygonArea -= Math.abs(signedArea(data, start, end, dim)); + } + } - var i = byteLength - 1 - var mul = 1 - var sub = value < 0 ? 1 : 0 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } + var trianglesArea = 0; + for (i = 0; i < triangles.length; i += 3) { + var a = triangles[i] * dim; + var b = triangles[i + 1] * dim; + var c = triangles[i + 2] * dim; + trianglesArea += Math.abs( + (data[a] - data[c]) * (data[b + 1] - data[a + 1]) - + (data[a] - data[b]) * (data[c + 1] - data[a + 1])); + } - return offset + byteLength -} + return polygonArea === 0 && trianglesArea === 0 ? 0 : + Math.abs((trianglesArea - polygonArea) / polygonArea); +}; -Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) - if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) - if (value < 0) value = 0xff + value + 1 - this[offset] = (value & 0xff) - return offset + 1 +function signedArea(data, start, end, dim) { + var sum = 0; + for (var i = start, j = end - dim; i < end; i += dim) { + sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]); + j = i; + } + return sum; } -Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } - return offset + 2 -} +// turn a polygon in a multi-dimensional array form (e.g. as in GeoJSON) into a form Earcut accepts +earcut.flatten = function (data) { + var dim = data[0][0].length, + result = {vertices: [], holes: [], dimensions: dim}, + holeIndex = 0; -Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - } else { - objectWriteUInt16(this, value, offset, false) - } - 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) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - this[offset + 2] = (value >>> 16) - this[offset + 3] = (value >>> 24) - } else { - objectWriteUInt32(this, value, offset, true) - } - 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 - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, false) - } - return offset + 4 -} + for (var i = 0; i < data.length; i++) { + for (var j = 0; j < data[i].length; j++) { + for (var d = 0; d < dim; d++) result.vertices.push(data[i][j][d]); + } + if (i > 0) { + holeIndex += data[i - 1].length; + result.holes.push(holeIndex); + } + } + return result; +}; -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') -} +},{}],12:[function(require,module,exports){ +'use strict'; -function writeFloat (buf, value, offset, littleEndian, noAssert) { - if (!noAssert) { - checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) - } - ieee754.write(buf, value, offset, littleEndian, 23, 4) - return offset + 4 -} +module.exports = createFilter; -Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { - return writeFloat(this, value, offset, true, noAssert) -} +var types = ['Unknown', 'Point', 'LineString', 'Polygon']; -Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { - return writeFloat(this, value, offset, false, noAssert) +/** + * Given a filter expressed as nested arrays, return a new function + * that evaluates whether a given feature (with a .properties or .tags property) + * passes its test. + * + * @param {Array} filter mapbox gl filter + * @returns {Function} filter-evaluating function + */ +function createFilter(filter) { + return new Function('f', 'var p = (f && f.properties || {}); return ' + compile(filter)); } -function writeDouble (buf, value, offset, littleEndian, noAssert) { - if (!noAssert) { - checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) - } - ieee754.write(buf, value, offset, littleEndian, 52, 8) - return offset + 8 +function compile(filter) { + if (!filter) return 'true'; + var op = filter[0]; + if (filter.length <= 1) return op === 'any' ? 'false' : 'true'; + var str = + op === '==' ? compileComparisonOp(filter[1], filter[2], '===', false) : + op === '!=' ? compileComparisonOp(filter[1], filter[2], '!==', false) : + op === '<' || + op === '>' || + op === '<=' || + op === '>=' ? compileComparisonOp(filter[1], filter[2], op, true) : + op === 'any' ? compileLogicalOp(filter.slice(1), '||') : + op === 'all' ? compileLogicalOp(filter.slice(1), '&&') : + op === 'none' ? compileNegation(compileLogicalOp(filter.slice(1), '||')) : + op === 'in' ? compileInOp(filter[1], filter.slice(2)) : + op === '!in' ? compileNegation(compileInOp(filter[1], filter.slice(2))) : + op === 'has' ? compileHasOp(filter[1]) : + op === '!has' ? compileNegation(compileHasOp([filter[1]])) : + 'true'; + return '(' + str + ')'; } -Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { - return writeDouble(this, value, offset, true, noAssert) +function compilePropertyReference(property) { + return property === '$type' ? 'f.type' : + property === '$id' ? 'f.id' : + 'p[' + JSON.stringify(property) + ']'; } -Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { - return writeDouble(this, value, offset, false, noAssert) +function compileComparisonOp(property, value, op, checkType) { + var left = compilePropertyReference(property); + var right = property === '$type' ? types.indexOf(value) : JSON.stringify(value); + return (checkType ? 'typeof ' + left + '=== typeof ' + right + '&&' : '') + left + op + right; } -// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) -Buffer.prototype.copy = function copy (target, targetStart, start, end) { - 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 +function compileLogicalOp(expressions, op) { + return expressions.map(compile).join(op); +} - // Copy 0 bytes; we're done - if (end === start) return 0 - if (target.length === 0 || this.length === 0) return 0 +function compileInOp(property, values) { + if (property === '$type') values = values.map(function(value) { return types.indexOf(value); }); + var left = JSON.stringify(values.sort(compare)); + var right = compilePropertyReference(property); - // Fatal error conditions - if (targetStart < 0) { - throw new RangeError('targetStart out of bounds') - } - if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') - if (end < 0) throw new RangeError('sourceEnd out of bounds') + if (values.length <= 200) return left + '.indexOf(' + right + ') !== -1'; - // Are we oob? - if (end > this.length) end = this.length - if (target.length - targetStart < end - start) { - end = target.length - targetStart + start - } + return 'function(v, a, i, j) {' + + 'while (i <= j) { var m = (i + j) >> 1;' + + ' if (a[m] === v) return true; if (a[m] > v) j = m - 1; else i = m + 1;' + + '}' + + 'return false; }(' + right + ', ' + left + ',0,' + (values.length - 1) + ')'; +} - var len = end - start - var i +function compileHasOp(property) { + return JSON.stringify(property) + ' in p'; +} - if (this === target && start < targetStart && targetStart < end) { - // descending copy from end - for (i = len - 1; i >= 0; i--) { - target[i + targetStart] = this[i + start] - } - } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { - // ascending copy from start - for (i = 0; i < len; i++) { - target[i + targetStart] = this[i + start] - } - } else { - Uint8Array.prototype.set.call( - target, - this.subarray(start, start + len), - targetStart - ) - } +function compileNegation(expression) { + return '!(' + expression + ')'; +} - return len +// Comparison function to sort numbers and strings +function compare(a, b) { + return a < b ? -1 : a > b ? 1 : 0; } -// fill(value, start=0, end=buffer.length) -Buffer.prototype.fill = function fill (value, start, end) { - if (!value) value = 0 - if (!start) start = 0 - if (!end) end = this.length +},{}],13:[function(require,module,exports){ +'use strict'; - if (end < start) throw new RangeError('end < start') +module.exports = decode; - // Fill 0 bytes; we're done - if (end === start) return - if (this.length === 0) return +var keys, values, lengths, dim, e; - if (start < 0 || start >= this.length) throw new RangeError('start out of bounds') - if (end < 0 || end > this.length) throw new RangeError('end out of bounds') +var geometryTypes = ['Point', 'MultiPoint', 'LineString', 'MultiLineString', + 'Polygon', 'MultiPolygon', 'GeometryCollection']; - var i - if (typeof value === 'number') { - for (i = start; i < end; i++) { - this[i] = value - } - } else { - var bytes = utf8ToBytes(value.toString()) - var len = bytes.length - for (i = start; i < end; i++) { - this[i] = bytes[i % len] - } - } +function decode(pbf) { + dim = 2; + e = Math.pow(10, 6); + lengths = null; - return this -} + keys = []; + values = []; + var obj = pbf.readFields(readDataField, {}); + keys = null; -// HELPER FUNCTIONS -// ================ + return obj; +} -var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g +function readDataField(tag, obj, pbf) { + if (tag === 1) keys.push(pbf.readString()); + else if (tag === 2) dim = pbf.readVarint(); + else if (tag === 3) e = Math.pow(10, pbf.readVarint()); -function base64clean (str) { - // Node strips out invalid characters like \n and \t from the string, base64-js does not - str = stringtrim(str).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 + else if (tag === 4) readFeatureCollection(pbf, obj); + else if (tag === 5) readFeature(pbf, obj); + else if (tag === 6) readGeometry(pbf, obj); } -function stringtrim (str) { - if (str.trim) return str.trim() - return str.replace(/^\s+|\s+$/g, '') +function readFeatureCollection(pbf, obj) { + obj.type = 'FeatureCollection'; + obj.features = []; + return pbf.readMessage(readFeatureCollectionField, obj); } -function toHex (n) { - if (n < 16) return '0' + n.toString(16) - return n.toString(16) +function readFeature(pbf, feature) { + feature.type = 'Feature'; + return pbf.readMessage(readFeatureField, feature); } -function utf8ToBytes (string, units) { - units = units || Infinity - var codePoint - var length = string.length - var leadSurrogate = null - var bytes = [] +function readGeometry(pbf, geom) { + return pbf.readMessage(readGeometryField, geom); +} - 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 - } +function readFeatureCollectionField(tag, obj, pbf) { + if (tag === 1) obj.features.push(readFeature(pbf, {})); - // 2 leads in a row - if (codePoint < 0xDC00) { - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - leadSurrogate = codePoint - continue - } + else if (tag === 13) values.push(readValue(pbf)); + else if (tag === 15) readProps(pbf, obj); +} - // 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') - } - } +function readFeatureField(tag, feature, pbf) { + if (tag === 1) feature.geometry = readGeometry(pbf, {}); - return bytes -} + else if (tag === 11) feature.id = pbf.readString(); + else if (tag === 12) feature.id = pbf.readSVarint(); -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 + else if (tag === 13) values.push(readValue(pbf)); + else if (tag === 14) feature.properties = readProps(pbf, {}); + else if (tag === 15) readProps(pbf, feature); } -function utf16leToBytes (str, units) { - var c, hi, lo - var byteArray = [] - for (var i = 0; i < str.length; i++) { - if ((units -= 2) < 0) break +function readGeometryField(tag, geom, pbf) { + if (tag === 1) geom.type = geometryTypes[pbf.readVarint()]; - c = str.charCodeAt(i) - hi = c >> 8 - lo = c % 256 - byteArray.push(lo) - byteArray.push(hi) - } - - return byteArray + else if (tag === 2) lengths = pbf.readPackedVarint(); + else if (tag === 3) readCoords(geom, pbf, geom.type); + else if (tag === 4) { + geom.geometries = geom.geometries || []; + geom.geometries.push(readGeometry(pbf, {})); + } + else if (tag === 13) values.push(readValue(pbf)); + else if (tag === 15) readProps(pbf, geom); } -function base64ToBytes (str) { - return base64.toByteArray(base64clean(str)) +function readCoords(geom, pbf, type) { + if (type === 'Point') geom.coordinates = readPoint(pbf); + else if (type === 'MultiPoint') geom.coordinates = readLine(pbf, true); + else if (type === 'LineString') geom.coordinates = readLine(pbf); + else if (type === 'MultiLineString') geom.coordinates = readMultiLine(pbf); + else if (type === 'Polygon') geom.coordinates = readMultiLine(pbf, true); + else if (type === 'MultiPolygon') geom.coordinates = readMultiPolygon(pbf); } -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 -} +function readValue(pbf) { + var end = pbf.readVarint() + pbf.pos, + value = null; -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"base64-js":4,"ieee754":5,"isarray":6}],4:[function(require,module,exports){ -;(function (exports) { - 'use strict' - - var i - var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' - var lookup = [] - for (i = 0; i < code.length; i++) { - lookup[i] = code[i] - } - var revLookup = [] + while (pbf.pos < end) { + var val = pbf.readVarint(), + tag = val >> 3; - for (i = 0; i < code.length; ++i) { - revLookup[code.charCodeAt(i)] = i - } - revLookup['-'.charCodeAt(0)] = 62 - revLookup['_'.charCodeAt(0)] = 63 + if (tag === 1) value = pbf.readString(); + else if (tag === 2) value = pbf.readDouble(); + else if (tag === 3) value = pbf.readVarint(); + else if (tag === 4) value = -pbf.readVarint(); + else if (tag === 5) value = pbf.readBoolean(); + else if (tag === 6) value = JSON.parse(pbf.readString()); + } + return value; +} - var Arr = (typeof Uint8Array !== 'undefined') - ? Uint8Array - : Array +function readProps(pbf, props) { + var end = pbf.readVarint() + pbf.pos; + while (pbf.pos < end) props[keys[pbf.readVarint()]] = values[pbf.readVarint()]; + values = []; + return props; +} - function decode (elt) { - var v = revLookup[elt.charCodeAt(0)] - return v !== undefined ? v : -1 - } +function readPoint(pbf) { + var end = pbf.readVarint() + pbf.pos, + coords = []; + while (pbf.pos < end) coords.push(pbf.readSVarint() / e); + return coords; +} - function b64ToByteArray (b64) { - var i, j, l, tmp, placeHolders, arr +function readLinePart(pbf, end, len, closed) { + var i = 0, + coords = [], + p, d; - if (b64.length % 4 > 0) { - throw new Error('Invalid string. Length must be a multiple of 4') - } + var prevP = []; + for (d = 0; d < dim; d++) prevP[d] = 0; - // the number of equal signs (place holders) - // if there are two placeholders, than the two characters before it - // represent one byte - // if there is only one, then the three characters before it represent 2 bytes - // this is just a cheap hack to not do indexOf twice - var len = b64.length - placeHolders = b64.charAt(len - 2) === '=' ? 2 : b64.charAt(len - 1) === '=' ? 1 : 0 + while (len ? i < len : pbf.pos < end) { + p = []; + for (d = 0; d < dim; d++) { + prevP[d] += pbf.readSVarint(); + p[d] = prevP[d] / e; + } + coords.push(p); + i++; + } + if (closed) coords.push(coords[0]); - // base64 is 4/3 + up to two characters of the original data - arr = new Arr(b64.length * 3 / 4 - placeHolders) + return coords; +} - // if there are placeholders, only get up to the last complete 4 chars - l = placeHolders > 0 ? b64.length - 4 : b64.length +function readLine(pbf) { + return readLinePart(pbf, pbf.readVarint() + pbf.pos); +} - var L = 0 +function readMultiLine(pbf, closed) { + var end = pbf.readVarint() + pbf.pos; + if (!lengths) return [readLinePart(pbf, end, null, closed)]; - function push (v) { - arr[L++] = v - } + var coords = []; + for (var i = 0; i < lengths.length; i++) coords.push(readLinePart(pbf, end, lengths[i], closed)); + lengths = null; + return coords; +} - for (i = 0, j = 0; i < l; i += 4, j += 3) { - tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3)) - push((tmp & 0xFF0000) >> 16) - push((tmp & 0xFF00) >> 8) - push(tmp & 0xFF) - } +function readMultiPolygon(pbf) { + var end = pbf.readVarint() + pbf.pos; + if (!lengths) return [[readLinePart(pbf, end, null, true)]]; - if (placeHolders === 2) { - tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4) - push(tmp & 0xFF) - } else if (placeHolders === 1) { - tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2) - push((tmp >> 8) & 0xFF) - push(tmp & 0xFF) + var coords = []; + var j = 1; + for (var i = 0; i < lengths[0]; i++) { + var rings = []; + for (var k = 0; k < lengths[j]; k++) rings.push(readLinePart(pbf, end, lengths[j + 1 + k], true)); + j += lengths[j] + 1; + coords.push(rings); } + lengths = null; + return coords; +} - return arr - } - - function encode (num) { - return lookup[num] - } +},{}],14:[function(require,module,exports){ +'use strict'; - function tripletToBase64 (num) { - return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F) - } +module.exports = encode; - function encodeChunk (uint8, start, end) { - var temp - var output = [] - for (var i = start; i < end; i += 3) { - temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) - output.push(tripletToBase64(temp)) - } - return output.join('') - } +var keys, keysNum, dim, e, + maxPrecision = 1e6; - function uint8ToBase64 (uint8) { - var i - var extraBytes = uint8.length % 3 // if we have 1 byte left, pad 2 bytes - var output = '' - var parts = [] - var temp, length - var maxChunkLength = 16383 // must be multiple of 3 - - // go through the array every three bytes, we'll deal with trailing stuff later - - for (i = 0, length = uint8.length - extraBytes; i < length; i += maxChunkLength) { - parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > length ? length : (i + maxChunkLength))) - } - - // pad the end with zeros, but make sure to not forget the extra bytes - switch (extraBytes) { - case 1: - temp = uint8[uint8.length - 1] - output += encode(temp >> 2) - output += encode((temp << 4) & 0x3F) - output += '==' - break - case 2: - temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]) - output += encode(temp >> 10) - output += encode((temp >> 4) & 0x3F) - output += encode((temp << 2) & 0x3F) - output += '=' - break - default: - break - } +var geometryTypes = { + 'Point': 0, + 'MultiPoint': 1, + 'LineString': 2, + 'MultiLineString': 3, + 'Polygon': 4, + 'MultiPolygon': 5, + 'GeometryCollection': 6 +}; - parts.push(output) +function encode(obj, pbf) { + keys = {}; + keysNum = 0; + dim = 0; + e = 1; - return parts.join('') - } + analyze(obj); - exports.toByteArray = b64ToByteArray - exports.fromByteArray = uint8ToBase64 -}(typeof exports === 'undefined' ? (this.base64js = {}) : exports)) + e = Math.min(e, maxPrecision); + var precision = Math.ceil(Math.log(e) / Math.LN10); -},{}],5:[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] + var keysArr = Object.keys(keys); - i += d + for (var i = 0; i < keysArr.length; i++) pbf.writeStringField(1, keysArr[i]); + if (dim !== 2) pbf.writeVarintField(2, dim); + if (precision !== 6) pbf.writeVarintField(3, precision); - e = s & ((1 << (-nBits)) - 1) - s >>= (-nBits) - nBits += eLen - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} + if (obj.type === 'FeatureCollection') pbf.writeMessage(4, writeFeatureCollection, obj); + else if (obj.type === 'Feature') pbf.writeMessage(5, writeFeature, obj); + else pbf.writeMessage(6, writeGeometry, obj); - m = e & ((1 << (-nBits)) - 1) - e >>= (-nBits) - nBits += mLen - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} + keys = null; - 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) + return pbf.finish(); } -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 +function analyze(obj) { + var i, key; - value = Math.abs(value) + if (obj.type === 'FeatureCollection') { + for (i = 0; i < obj.features.length; i++) analyze(obj.features[i]); - 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) + } else if (obj.type === 'Feature') { + analyze(obj.geometry); + for (key in obj.properties) saveKey(key); + + } else if (obj.type === 'Point') analyzePoint(obj.coordinates); + else if (obj.type === 'MultiPoint') analyzePoints(obj.coordinates); + else if (obj.type === 'GeometryCollection') { + for (i = 0; i < obj.geometries.length; i++) analyze(obj.geometries[i]); } - if (value * c >= 2) { - e++ - c /= 2 + else if (obj.type === 'LineString') analyzePoints(obj.coordinates); + else if (obj.type === 'Polygon' || obj.type === 'MultiLineString') analyzeMultiLine(obj.coordinates); + else if (obj.type === 'MultiPolygon') { + for (i = 0; i < obj.coordinates.length; i++) analyzeMultiLine(obj.coordinates[i]); } - 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 (key in obj) { + if (!isSpecialKey(key, obj.type)) saveKey(key); } - } - - 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 +function analyzeMultiLine(coords) { + for (var i = 0; i < coords.length; i++) analyzePoints(coords[i]); } -},{}],6:[function(require,module,exports){ -var toString = {}.toString; +function analyzePoints(coords) { + for (var i = 0; i < coords.length; i++) analyzePoint(coords[i]); +} -module.exports = Array.isArray || function (arr) { - return toString.call(arr) == '[object Array]'; -}; +function analyzePoint(point) { + dim = Math.max(dim, point.length); -},{}],7:[function(require,module,exports){ -if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; -} else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } + // find max precision + for (var i = 0; i < point.length; i++) { + while (Math.round(point[i] * e) / e !== point[i] && e < maxPrecision) e *= 10; + } } -},{}],8:[function(require,module,exports){ -(function (process){ -// 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. +function saveKey(key) { + if (keys[key] === undefined) keys[key] = keysNum++; +} -// resolves . and .. elements in a path array with directory names there -// must be no slashes, empty elements, or device names (c:\) in the array -// (so also no leading and trailing slashes - it does not distinguish -// relative and absolute paths) -function normalizeArray(parts, allowAboveRoot) { - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = parts.length - 1; i >= 0; i--) { - var last = parts[i]; - if (last === '.') { - parts.splice(i, 1); - } else if (last === '..') { - parts.splice(i, 1); - up++; - } else if (up) { - parts.splice(i, 1); - up--; +function writeFeatureCollection(obj, pbf) { + for (var i = 0; i < obj.features.length; i++) { + pbf.writeMessage(1, writeFeature, obj.features[i]); } - } + writeProps(obj, pbf, true); +} - // if the path is allowed to go above the root, restore leading ..s - if (allowAboveRoot) { - for (; up--; up) { - parts.unshift('..'); +function writeFeature(feature, pbf) { + pbf.writeMessage(1, writeGeometry, feature.geometry); + + if (feature.id !== undefined) { + if (typeof feature.id === 'number' && feature.id % 1 === 0) pbf.writeSVarintField(12, feature.id); + else pbf.writeStringField(11, feature.id); } - } - return parts; + if (feature.properties) writeProps(feature.properties, pbf); + writeProps(feature, pbf, true); } -// Split a filename into [root, dir, basename, ext], unix version -// 'root' is just a slash, or nothing. -var splitPathRe = - /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; -var splitPath = function(filename) { - return splitPathRe.exec(filename).slice(1); -}; - -// path.resolve([from ...], to) -// posix version -exports.resolve = function() { - var resolvedPath = '', - resolvedAbsolute = false; +function writeGeometry(geom, pbf) { + pbf.writeVarintField(1, geometryTypes[geom.type]); - for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = (i >= 0) ? arguments[i] : process.cwd(); + var coords = geom.coordinates; - // Skip empty and invalid entries - if (typeof path !== 'string') { - throw new TypeError('Arguments to path.resolve must be strings'); - } else if (!path) { - continue; + if (geom.type === 'Point') writePoint(coords, pbf); + else if (geom.type === 'MultiPoint') writeLine(coords, pbf, true); + else if (geom.type === 'LineString') writeLine(coords, pbf); + else if (geom.type === 'MultiLineString') writeMultiLine(coords, pbf); + else if (geom.type === 'Polygon') writeMultiLine(coords, pbf, true); + else if (geom.type === 'MultiPolygon') writeMultiPolygon(coords, pbf); + else if (geom.type === 'GeometryCollection') { + for (var i = 0; i < geom.geometries.length; i++) pbf.writeMessage(4, writeGeometry, geom.geometries[i]); } - resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = path.charAt(0) === '/'; - } + writeProps(geom, pbf, true); +} - // At this point the path should be resolved to a full absolute path, but - // handle relative paths to be safe (might happen when process.cwd() fails) +function writeProps(props, pbf, isCustom) { + var indexes = [], + valueIndex = 0; - // Normalize the path - resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { - return !!p; - }), !resolvedAbsolute).join('/'); + for (var key in props) { + if (isCustom && isSpecialKey(key, props.type)) { + continue; + } + pbf.writeMessage(13, writeValue, props[key]); + indexes.push(keys[key]); + indexes.push(valueIndex++); + } + pbf.writePackedVarint(isCustom ? 15 : 14, indexes); +} - return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; -}; +function writeValue(value, pbf) { + var type = typeof value; -// path.normalize(path) -// posix version -exports.normalize = function(path) { - var isAbsolute = exports.isAbsolute(path), - trailingSlash = substr(path, -1) === '/'; + if (type === 'string') pbf.writeStringField(1, value); + else if (type === 'boolean') pbf.writeBooleanField(5, value); + else if (type === 'object') pbf.writeStringField(6, JSON.stringify(value)); + else if (type === 'number') { + if (value % 1 !== 0) pbf.writeDoubleField(2, value); + else if (value >= 0) pbf.writeVarintField(3, value); + else pbf.writeVarintField(4, -value); + } +} - // Normalize the path - path = normalizeArray(filter(path.split('/'), function(p) { - return !!p; - }), !isAbsolute).join('/'); +function writePoint(point, pbf) { + var coords = []; + for (var i = 0; i < dim; i++) coords.push(Math.round(point[i] * e)); + pbf.writePackedSVarint(3, coords); +} - if (!path && !isAbsolute) { - path = '.'; - } - if (path && trailingSlash) { - path += '/'; - } +function writeLine(line, pbf) { + var coords = []; + populateLine(coords, line); + pbf.writePackedSVarint(3, coords); +} - return (isAbsolute ? '/' : '') + path; -}; +function writeMultiLine(lines, pbf, closed) { + var len = lines.length, + i; + if (len !== 1) { + var lengths = []; + for (i = 0; i < len; i++) lengths.push(lines[i].length - (closed ? 1 : 0)); + pbf.writePackedVarint(2, lengths); + // TODO faster with custom writeMessage? + } + var coords = []; + for (i = 0; i < len; i++) populateLine(coords, lines[i], closed); + pbf.writePackedSVarint(3, coords); +} -// posix version -exports.isAbsolute = function(path) { - return path.charAt(0) === '/'; -}; +function writeMultiPolygon(polygons, pbf) { + var len = polygons.length, + i, j; + if (len !== 1 || polygons[0].length !== 1) { + var lengths = [len]; + for (i = 0; i < len; i++) { + lengths.push(polygons[i].length); + for (j = 0; j < polygons[i].length; j++) lengths.push(polygons[i][j].length - 1); + } + pbf.writePackedVarint(2, lengths); + } -// posix version -exports.join = function() { - var paths = Array.prototype.slice.call(arguments, 0); - return exports.normalize(filter(paths, function(p, index) { - if (typeof p !== 'string') { - throw new TypeError('Arguments to path.join must be strings'); + var coords = []; + for (i = 0; i < len; i++) { + for (j = 0; j < polygons[i].length; j++) populateLine(coords, polygons[i][j], true); } - return p; - }).join('/')); -}; + pbf.writePackedSVarint(3, coords); +} +function populateLine(coords, line, closed) { + var i, j, + len = line.length - (closed ? 1 : 0), + sum = new Array(dim); + for (j = 0; j < dim; j++) sum[j] = 0; + for (i = 0; i < len; i++) { + for (j = 0; j < dim; j++) { + var n = Math.round(line[i][j] * e) - sum[j]; + coords.push(n); + sum[j] += n; + } + } +} -// path.relative(from, to) -// posix version -exports.relative = function(from, to) { - from = exports.resolve(from).substr(1); - to = exports.resolve(to).substr(1); +function isSpecialKey(key, type) { + if (key === 'type') return true; + else if (type === 'FeatureCollection') { + if (key === 'features') return true; + } else if (type === 'Feature') { + if (key === 'id' || key === 'properties' || key === 'geometry') return true; + } else if (type === 'GeometryCollection') { + if (key === 'geometries') return true; + } else if (key === 'coordinates') return true; + return false; +} - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== '') break; - } +},{}],15:[function(require,module,exports){ +'use strict'; - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== '') break; - } +exports.encode = require('./encode'); +exports.decode = require('./decode'); - if (start > end) return []; - return arr.slice(start, end - start + 1); - } +},{"./decode":13,"./encode":14}],16:[function(require,module,exports){ +var wgs84 = require('wgs84'); - var fromParts = trim(from.split('/')); - var toParts = trim(to.split('/')); +module.exports.geometry = geometry; +module.exports.ring = ringArea; - var length = Math.min(fromParts.length, toParts.length); - var samePartsLength = length; - for (var i = 0; i < length; i++) { - if (fromParts[i] !== toParts[i]) { - samePartsLength = i; - break; +function geometry(_) { + if (_.type === 'Polygon') return polygonArea(_.coordinates); + else if (_.type === 'MultiPolygon') { + var area = 0; + for (var i = 0; i < _.coordinates.length; i++) { + area += polygonArea(_.coordinates[i]); + } + return area; + } else { + return null; } - } - - var outputParts = []; - for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push('..'); - } +} - outputParts = outputParts.concat(toParts.slice(samePartsLength)); +function polygonArea(coords) { + var area = 0; + if (coords && coords.length > 0) { + area += Math.abs(ringArea(coords[0])); + for (var i = 1; i < coords.length; i++) { + area -= Math.abs(ringArea(coords[i])); + } + } + return area; +} - return outputParts.join('/'); -}; +/** + * Calculate the approximate area of the polygon were it projected onto + * the earth. Note that this area will be positive if ring is oriented + * clockwise, otherwise it will be negative. + * + * Reference: + * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for + * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion + * Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409 + * + * Returns: + * {float} The approximate signed geodesic area of the polygon in square + * meters. + */ -exports.sep = '/'; -exports.delimiter = ':'; +function ringArea(coords) { + var area = 0; -exports.dirname = function(path) { - var result = splitPath(path), - root = result[0], - dir = result[1]; + if (coords.length > 2) { + var p1, p2; + for (var i = 0; i < coords.length - 1; i++) { + p1 = coords[i]; + p2 = coords[i + 1]; + area += rad(p2[0] - p1[0]) * (2 + Math.sin(rad(p1[1])) + Math.sin(rad(p2[1]))); + } - if (!root && !dir) { - // No dirname whatsoever - return '.'; - } + area = area * wgs84.RADIUS * wgs84.RADIUS / 2; + } - if (dir) { - // It has a dirname, strip trailing slash - dir = dir.substr(0, dir.length - 1); - } + return area; +} - return root + dir; -}; +function rad(_) { + return _ * Math.PI / 180; +} +},{"wgs84":222}],17:[function(require,module,exports){ +var geojsonArea = require('geojson-area'); -exports.basename = function(path, ext) { - var f = splitPath(path)[2]; - // TODO: make this comparison case-insensitive on windows? - if (ext && f.substr(-1 * ext.length) === ext) { - f = f.substr(0, f.length - ext.length); - } - return f; -}; +module.exports = rewind; +function rewind(gj, outer) { + switch ((gj && gj.type) || null) { + case 'FeatureCollection': + gj.features = gj.features.map(curryOuter(rewind, outer)); + return gj; + case 'Feature': + gj.geometry = rewind(gj.geometry, outer); + return gj; + case 'Polygon': + case 'MultiPolygon': + return correct(gj, outer); + default: + return gj; + } +} -exports.extname = function(path) { - return splitPath(path)[3]; -}; +function curryOuter(a, b) { + return function(_) { return a(_, b); }; +} -function filter (xs, f) { - if (xs.filter) return xs.filter(f); - var res = []; - for (var i = 0; i < xs.length; i++) { - if (f(xs[i], i, xs)) res.push(xs[i]); +function correct(_, outer) { + if (_.type === 'Polygon') { + _.coordinates = correctRings(_.coordinates, outer); + } else if (_.type === 'MultiPolygon') { + _.coordinates = _.coordinates.map(curryOuter(correctRings, outer)); } - return res; + return _; } -// String.prototype.substr - negative index don't work in IE8 -var substr = 'ab'.substr(-1) === 'b' - ? function (str, start, len) { return str.substr(start, len) } - : function (str, start, len) { - if (start < 0) start = str.length + start; - return str.substr(start, len); +function correctRings(_, outer) { + outer = !!outer; + _[0] = wind(_[0], !outer); + for (var i = 1; i < _.length; i++) { + _[i] = wind(_[i], outer); } -; - -}).call(this,require('_process')) -},{"_process":9}],9:[function(require,module,exports){ -// shim for using process in browser + return _; +} -var process = module.exports = {}; -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; +function wind(_, dir) { + return cw(_) === dir ? _ : _.reverse(); +} -function cleanUpNextTick() { - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } +function cw(_) { + return geojsonArea.ring(_) >= 0; } -function drainQueue() { - if (draining) { - return; - } - var timeout = setTimeout(cleanUpNextTick); - draining = true; +},{"geojson-area":16}],18:[function(require,module,exports){ +'use strict'; - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } +module.exports = clip; + +var createFeature = require('./feature'); + +/* clip features between two axis-parallel lines: + * | | + * ___|___ | / + * / | \____|____/ + * | | + */ + +function clip(features, scale, k1, k2, axis, intersect, minAll, maxAll) { + + k1 /= scale; + k2 /= scale; + + if (minAll >= k1 && maxAll <= k2) return features; // trivial accept + else if (minAll > k2 || maxAll < k1) return null; // trivial reject + + var clipped = []; + + for (var i = 0; i < features.length; i++) { + + var feature = features[i], + geometry = feature.geometry, + type = feature.type, + min, max; + + min = feature.min[axis]; + max = feature.max[axis]; + + if (min >= k1 && max <= k2) { // trivial accept + clipped.push(feature); + continue; + } else if (min > k2 || max < k1) continue; // trivial reject + + var slices = type === 1 ? + clipPoints(geometry, k1, k2, axis) : + clipGeometry(geometry, k1, k2, axis, intersect, type === 3); + + if (slices.length) { + // if a feature got clipped, it will likely get clipped on the next zoom level as well, + // so there's no need to recalculate bboxes + clipped.push(createFeature(feature.tags, type, slices, feature.id)); } - queueIndex = -1; - len = queue.length; } - currentQueue = null; - draining = false; - clearTimeout(timeout); + + return clipped.length ? clipped : null; } -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) { - setTimeout(drainQueue, 0); - } -}; +function clipPoints(geometry, k1, k2, axis) { + var slice = []; -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; + for (var i = 0; i < geometry.length; i++) { + var a = geometry[i], + ak = a[axis]; + + if (ak >= k1 && ak <= k2) slice.push(a); + } + return slice; } -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() {} +function clipGeometry(geometry, k1, k2, axis, intersect, closed) { -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; + var slices = []; -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; + for (var i = 0; i < geometry.length; i++) { -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; + var ak = 0, + bk = 0, + b = null, + points = geometry[i], + area = points.area, + dist = points.dist, + outer = points.outer, + len = points.length, + a, j, last; -},{}],10:[function(require,module,exports){ -module.exports = function isBuffer(arg) { - return arg && typeof arg === 'object' - && typeof arg.copy === 'function' - && typeof arg.fill === 'function' - && typeof arg.readUInt8 === 'function'; -} -},{}],11:[function(require,module,exports){ -(function (process,global){ -// 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. - -var formatRegExp = /%[sdj%]/g; -exports.format = function(f) { - if (!isString(f)) { - var objects = []; - for (var i = 0; i < arguments.length; i++) { - objects.push(inspect(arguments[i])); - } - return objects.join(' '); - } + var slice = []; - var i = 1; - var args = arguments; - var len = args.length; - var str = String(f).replace(formatRegExp, function(x) { - if (x === '%%') return '%'; - if (i >= len) return x; - switch (x) { - case '%s': return String(args[i++]); - case '%d': return Number(args[i++]); - case '%j': - try { - return JSON.stringify(args[i++]); - } catch (_) { - return '[Circular]'; - } - default: - return x; - } - }); - for (var x = args[i]; i < len; x = args[++i]) { - if (isNull(x) || !isObject(x)) { - str += ' ' + x; - } else { - str += ' ' + inspect(x); - } - } - return str; -}; + for (j = 0; j < len - 1; j++) { + a = b || points[j]; + b = points[j + 1]; + ak = bk || a[axis]; + bk = b[axis]; + if (ak < k1) { -// Mark that a method should not be used. -// Returns a modified function which warns once by default. -// If --no-deprecation is set, then it is a no-op. -exports.deprecate = function(fn, msg) { - // Allow for deprecating things in the process of starting up. - if (isUndefined(global.process)) { - return function() { - return exports.deprecate(fn, msg).apply(this, arguments); - }; - } + if ((bk > k2)) { // ---|-----|--> + slice.push(intersect(a, b, k1), intersect(a, b, k2)); + if (!closed) slice = newSlice(slices, slice, area, dist, outer); - if (process.noDeprecation === true) { - return fn; - } + } else if (bk >= k1) slice.push(intersect(a, b, k1)); // ---|--> | - var warned = false; - function deprecated() { - if (!warned) { - if (process.throwDeprecation) { - throw new Error(msg); - } else if (process.traceDeprecation) { - console.trace(msg); - } else { - console.error(msg); - } - warned = true; - } - return fn.apply(this, arguments); - } + } else if (ak > k2) { - return deprecated; -}; + if ((bk < k1)) { // <--|-----|--- + slice.push(intersect(a, b, k2), intersect(a, b, k1)); + if (!closed) slice = newSlice(slices, slice, area, dist, outer); + } else if (bk <= k2) slice.push(intersect(a, b, k2)); // | <--|--- -var debugs = {}; -var debugEnviron; -exports.debuglog = function(set) { - if (isUndefined(debugEnviron)) - debugEnviron = process.env.NODE_DEBUG || ''; - set = set.toUpperCase(); - if (!debugs[set]) { - if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { - var pid = process.pid; - debugs[set] = function() { - var msg = exports.format.apply(exports, arguments); - console.error('%s %d: %s', set, pid, msg); - }; - } else { - debugs[set] = function() {}; - } - } - return debugs[set]; -}; + } else { + slice.push(a); -/** - * Echos the value of a value. Trys to print the value out - * in the best way possible given the different types. - * - * @param {Object} obj The object to print out. - * @param {Object} opts Optional options object that alters the output. - */ -/* legacy: obj, showHidden, depth, colors*/ -function inspect(obj, opts) { - // default options - var ctx = { - seen: [], - stylize: stylizeNoColor - }; - // legacy... - if (arguments.length >= 3) ctx.depth = arguments[2]; - if (arguments.length >= 4) ctx.colors = arguments[3]; - if (isBoolean(opts)) { - // legacy... - ctx.showHidden = opts; - } else if (opts) { - // got an "options" object - exports._extend(ctx, opts); - } - // set default options - if (isUndefined(ctx.showHidden)) ctx.showHidden = false; - if (isUndefined(ctx.depth)) ctx.depth = 2; - if (isUndefined(ctx.colors)) ctx.colors = false; - if (isUndefined(ctx.customInspect)) ctx.customInspect = true; - if (ctx.colors) ctx.stylize = stylizeWithColor; - return formatValue(ctx, obj, ctx.depth); -} -exports.inspect = inspect; + if (bk < k1) { // <--|--- | + slice.push(intersect(a, b, k1)); + if (!closed) slice = newSlice(slices, slice, area, dist, outer); + } else if (bk > k2) { // | ---|--> + slice.push(intersect(a, b, k2)); + if (!closed) slice = newSlice(slices, slice, area, dist, outer); + } + // | --> | + } + } -// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics -inspect.colors = { - 'bold' : [1, 22], - 'italic' : [3, 23], - 'underline' : [4, 24], - 'inverse' : [7, 27], - 'white' : [37, 39], - 'grey' : [90, 39], - 'black' : [30, 39], - 'blue' : [34, 39], - 'cyan' : [36, 39], - 'green' : [32, 39], - 'magenta' : [35, 39], - 'red' : [31, 39], - 'yellow' : [33, 39] -}; + // add the last point + a = points[len - 1]; + ak = a[axis]; + if (ak >= k1 && ak <= k2) slice.push(a); -// Don't use 'blue' not visible on cmd.exe -inspect.styles = { - 'special': 'cyan', - 'number': 'yellow', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'date': 'magenta', - // "name": intentionally not styling - 'regexp': 'red' -}; + // close the polygon if its endpoints are not the same after clipping + last = slice[slice.length - 1]; + if (closed && last && (slice[0][0] !== last[0] || slice[0][1] !== last[1])) slice.push(slice[0]); -function stylizeWithColor(str, styleType) { - var style = inspect.styles[styleType]; + // add the final slice + newSlice(slices, slice, area, dist, outer); + } - if (style) { - return '\u001b[' + inspect.colors[style][0] + 'm' + str + - '\u001b[' + inspect.colors[style][1] + 'm'; - } else { - return str; - } + return slices; } +function newSlice(slices, slice, area, dist, outer) { + if (slice.length) { + // we don't recalculate the area/length of the unclipped geometry because the case where it goes + // below the visibility threshold as a result of clipping is rare, so we avoid doing unnecessary work + slice.area = area; + slice.dist = dist; + if (outer !== undefined) slice.outer = outer; -function stylizeNoColor(str, styleType) { - return str; + slices.push(slice); + } + return []; } +},{"./feature":20}],19:[function(require,module,exports){ +'use strict'; -function arrayToHash(array) { - var hash = {}; +module.exports = convert; - array.forEach(function(val, idx) { - hash[val] = true; - }); +var simplify = require('./simplify'); +var createFeature = require('./feature'); - return hash; -} +// converts GeoJSON feature into an intermediate projected JSON vector format with simplification data +function convert(data, tolerance) { + var features = []; -function formatValue(ctx, value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (ctx.customInspect && - value && - isFunction(value.inspect) && - // Filter out the util module, it's inspect function is special - value.inspect !== exports.inspect && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - var ret = value.inspect(recurseTimes, ctx); - if (!isString(ret)) { - ret = formatValue(ctx, ret, recurseTimes); - } - return ret; - } + if (data.type === 'FeatureCollection') { + for (var i = 0; i < data.features.length; i++) { + convertFeature(features, data.features[i], tolerance); + } + } else if (data.type === 'Feature') { + convertFeature(features, data, tolerance); - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; - } - - // Look up the keys of the object. - var keys = Object.keys(value); - var visibleKeys = arrayToHash(keys); - - if (ctx.showHidden) { - keys = Object.getOwnPropertyNames(value); - } - - // IE doesn't make error fields non-enumerable - // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx - if (isError(value) - && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { - return formatError(value); - } - - // Some type of object without properties can be shortcutted. - if (keys.length === 0) { - if (isFunction(value)) { - var name = value.name ? ': ' + value.name : ''; - return ctx.stylize('[Function' + name + ']', 'special'); - } - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } - if (isDate(value)) { - return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } else { + // single geometry or a geometry collection + convertFeature(features, {geometry: data}, tolerance); } - if (isError(value)) { - return formatError(value); + return features; +} + +function convertFeature(features, feature, tolerance) { + if (feature.geometry === null) { + // ignore features with null geometry + return; } - } - var base = '', array = false, braces = ['{', '}']; + var geom = feature.geometry, + type = geom.type, + coords = geom.coordinates, + tags = feature.properties, + id = feature.id, + i, j, rings, projectedRing; - // Make Array say that they are Array - if (isArray(value)) { - array = true; - braces = ['[', ']']; - } + if (type === 'Point') { + features.push(createFeature(tags, 1, [projectPoint(coords)], id)); - // Make functions say that they are functions - if (isFunction(value)) { - var n = value.name ? ': ' + value.name : ''; - base = ' [Function' + n + ']'; - } + } else if (type === 'MultiPoint') { + features.push(createFeature(tags, 1, project(coords), id)); - // Make RegExps say that they are RegExps - if (isRegExp(value)) { - base = ' ' + RegExp.prototype.toString.call(value); - } + } else if (type === 'LineString') { + features.push(createFeature(tags, 2, [project(coords, tolerance)], id)); - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + Date.prototype.toUTCString.call(value); - } + } else if (type === 'MultiLineString' || type === 'Polygon') { + rings = []; + for (i = 0; i < coords.length; i++) { + projectedRing = project(coords[i], tolerance); + if (type === 'Polygon') projectedRing.outer = (i === 0); + rings.push(projectedRing); + } + features.push(createFeature(tags, type === 'Polygon' ? 3 : 2, rings, id)); - // Make error with message first say the error - if (isError(value)) { - base = ' ' + formatError(value); - } + } else if (type === 'MultiPolygon') { + rings = []; + for (i = 0; i < coords.length; i++) { + for (j = 0; j < coords[i].length; j++) { + projectedRing = project(coords[i][j], tolerance); + projectedRing.outer = (j === 0); + rings.push(projectedRing); + } + } + features.push(createFeature(tags, 3, rings, id)); - if (keys.length === 0 && (!array || value.length == 0)) { - return braces[0] + base + braces[1]; - } + } else if (type === 'GeometryCollection') { + for (i = 0; i < geom.geometries.length; i++) { + convertFeature(features, { + geometry: geom.geometries[i], + properties: tags + }, tolerance); + } - if (recurseTimes < 0) { - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); } else { - return ctx.stylize('[Object]', 'special'); + throw new Error('Input data is not a valid GeoJSON object.'); } - } +} - ctx.seen.push(value); +function project(lonlats, tolerance) { + var projected = []; + for (var i = 0; i < lonlats.length; i++) { + projected.push(projectPoint(lonlats[i])); + } + if (tolerance) { + simplify(projected, tolerance); + calcSize(projected); + } + return projected; +} - var output; - if (array) { - output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); - } else { - output = keys.map(function(key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); - } +function projectPoint(p) { + var sin = Math.sin(p[1] * Math.PI / 180), + x = (p[0] / 360 + 0.5), + y = (0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI); - ctx.seen.pop(); + y = y < 0 ? 0 : + y > 1 ? 1 : y; - return reduceToSingleString(output, base, braces); + return [x, y, 0]; } +// calculate area and length of the poly +function calcSize(points) { + var area = 0, + dist = 0; -function formatPrimitive(ctx, value) { - if (isUndefined(value)) - return ctx.stylize('undefined', 'undefined'); - if (isString(value)) { - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return ctx.stylize(simple, 'string'); - } - if (isNumber(value)) - return ctx.stylize('' + value, 'number'); - if (isBoolean(value)) - return ctx.stylize('' + value, 'boolean'); - // For some reason typeof null is "object", so special case here. - if (isNull(value)) - return ctx.stylize('null', 'null'); -} + for (var i = 0, a, b; i < points.length - 1; i++) { + a = b || points[i]; + b = points[i + 1]; + area += a[0] * b[1] - b[0] * a[1]; -function formatError(value) { - return '[' + Error.prototype.toString.call(value) + ']'; + // use Manhattan distance instead of Euclidian one to avoid expensive square root computation + dist += Math.abs(b[0] - a[0]) + Math.abs(b[1] - a[1]); + } + points.area = Math.abs(area / 2); + points.dist = dist; } +},{"./feature":20,"./simplify":22}],20:[function(require,module,exports){ +'use strict'; -function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - for (var i = 0, l = value.length; i < l; ++i) { - if (hasOwnProperty(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); - } else { - output.push(''); - } - } - keys.forEach(function(key) { - if (!key.match(/^\d+$/)) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - key, true)); - } - }); - return output; +module.exports = createFeature; + +function createFeature(tags, type, geom, id) { + var feature = { + id: id || null, + type: type, + geometry: geom, + tags: tags || null, + min: [Infinity, Infinity], // initial bbox values + max: [-Infinity, -Infinity] + }; + calcBBox(feature); + return feature; } +// calculate the feature bounding box for faster clipping later +function calcBBox(feature) { + var geometry = feature.geometry, + min = feature.min, + max = feature.max; -function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { - var name, str, desc; - desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; - if (desc.get) { - if (desc.set) { - str = ctx.stylize('[Getter/Setter]', 'special'); + if (feature.type === 1) { + calcRingBBox(min, max, geometry); } else { - str = ctx.stylize('[Getter]', 'special'); - } - } else { - if (desc.set) { - str = ctx.stylize('[Setter]', 'special'); - } - } - if (!hasOwnProperty(visibleKeys, key)) { - name = '[' + key + ']'; - } - if (!str) { - if (ctx.seen.indexOf(desc.value) < 0) { - if (isNull(recurseTimes)) { - str = formatValue(ctx, desc.value, null); - } else { - str = formatValue(ctx, desc.value, recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (array) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); + for (var i = 0; i < geometry.length; i++) { + calcRingBBox(min, max, geometry[i]); } - } - } else { - str = ctx.stylize('[Circular]', 'special'); - } - } - if (isUndefined(name)) { - if (array && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = ctx.stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = ctx.stylize(name, 'string'); } - } - return name + ': ' + str; + return feature; } +function calcRingBBox(min, max, points) { + for (var i = 0, p; i < points.length; i++) { + p = points[i]; + min[0] = Math.min(p[0], min[0]); + max[0] = Math.max(p[0], max[0]); + min[1] = Math.min(p[1], min[1]); + max[1] = Math.max(p[1], max[1]); + } +} -function reduceToSingleString(output, base, braces) { - var numLinesEst = 0; - var length = output.reduce(function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; - }, 0); +},{}],21:[function(require,module,exports){ +'use strict'; - if (length > 60) { - return braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; - } +module.exports = geojsonvt; - return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; -} +var convert = require('./convert'), // GeoJSON conversion and preprocessing + transform = require('./transform'), // coordinate transformation + clip = require('./clip'), // stripe clipping algorithm + wrap = require('./wrap'), // date line processing + createTile = require('./tile'); // final simplified tile generation -// NOTE: These type checking functions intentionally don't use `instanceof` -// because it is fragile and can be easily faked with `Object.create()`. -function isArray(ar) { - return Array.isArray(ar); +function geojsonvt(data, options) { + return new GeoJSONVT(data, options); } -exports.isArray = isArray; -function isBoolean(arg) { - return typeof arg === 'boolean'; -} -exports.isBoolean = isBoolean; +function GeoJSONVT(data, options) { + options = this.options = extend(Object.create(this.options), options); -function isNull(arg) { - return arg === null; -} -exports.isNull = isNull; + var debug = options.debug; -function isNullOrUndefined(arg) { - return arg == null; -} -exports.isNullOrUndefined = isNullOrUndefined; + if (debug) console.time('preprocess data'); -function isNumber(arg) { - return typeof arg === 'number'; -} -exports.isNumber = isNumber; + var z2 = 1 << options.maxZoom, // 2^z + features = convert(data, options.tolerance / (z2 * options.extent)); -function isString(arg) { - return typeof arg === 'string'; -} -exports.isString = isString; + this.tiles = {}; + this.tileCoords = []; -function isSymbol(arg) { - return typeof arg === 'symbol'; -} -exports.isSymbol = isSymbol; + if (debug) { + console.timeEnd('preprocess data'); + console.log('index: maxZoom: %d, maxPoints: %d', options.indexMaxZoom, options.indexMaxPoints); + console.time('generate tiles'); + this.stats = {}; + this.total = 0; + } -function isUndefined(arg) { - return arg === void 0; -} -exports.isUndefined = isUndefined; + features = wrap(features, options.buffer / options.extent, intersectX); -function isRegExp(re) { - return isObject(re) && objectToString(re) === '[object RegExp]'; -} -exports.isRegExp = isRegExp; + // start slicing from the top tile down + if (features.length) this.splitTile(features, 0, 0, 0); -function isObject(arg) { - return typeof arg === 'object' && arg !== null; + if (debug) { + if (features.length) console.log('features: %d, points: %d', this.tiles[0].numFeatures, this.tiles[0].numPoints); + console.timeEnd('generate tiles'); + console.log('tiles generated:', this.total, JSON.stringify(this.stats)); + } } -exports.isObject = isObject; -function isDate(d) { - return isObject(d) && objectToString(d) === '[object Date]'; -} -exports.isDate = isDate; +GeoJSONVT.prototype.options = { + maxZoom: 14, // max zoom to preserve detail on + indexMaxZoom: 5, // max zoom in the tile index + indexMaxPoints: 100000, // max number of points per tile in the tile index + solidChildren: false, // whether to tile solid square tiles further + tolerance: 3, // simplification tolerance (higher means simpler) + extent: 4096, // tile extent + buffer: 64, // tile buffer on each side + debug: 0 // logging level (0, 1 or 2) +}; -function isError(e) { - return isObject(e) && - (objectToString(e) === '[object Error]' || e instanceof Error); -} -exports.isError = isError; +GeoJSONVT.prototype.splitTile = function (features, z, x, y, cz, cx, cy) { -function isFunction(arg) { - return typeof arg === 'function'; -} -exports.isFunction = isFunction; + var stack = [features, z, x, y], + options = this.options, + debug = options.debug, + solid = null; -function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; -} -exports.isPrimitive = isPrimitive; + // avoid recursion by using a processing queue + while (stack.length) { + y = stack.pop(); + x = stack.pop(); + z = stack.pop(); + features = stack.pop(); -exports.isBuffer = require('./support/isBuffer'); + var z2 = 1 << z, + id = toID(z, x, y), + tile = this.tiles[id], + tileTolerance = z === options.maxZoom ? 0 : options.tolerance / (z2 * options.extent); -function objectToString(o) { - return Object.prototype.toString.call(o); -} + if (!tile) { + if (debug > 1) console.time('creation'); + tile = this.tiles[id] = createTile(features, z2, x, y, tileTolerance, z === options.maxZoom); + this.tileCoords.push({z: z, x: x, y: y}); -function pad(n) { - return n < 10 ? '0' + n.toString(10) : n.toString(10); -} + if (debug) { + if (debug > 1) { + console.log('tile z%d-%d-%d (features: %d, points: %d, simplified: %d)', + z, x, y, tile.numFeatures, tile.numPoints, tile.numSimplified); + console.timeEnd('creation'); + } + var key = 'z' + z; + this.stats[key] = (this.stats[key] || 0) + 1; + this.total++; + } + } + // save reference to original geometry in tile so that we can drill down later if we stop now + tile.source = features; -var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', - 'Oct', 'Nov', 'Dec']; + // if it's the first-pass tiling + if (!cz) { + // stop tiling if we reached max zoom, or if the tile is too simple + if (z === options.indexMaxZoom || tile.numPoints <= options.indexMaxPoints) continue; -// 26 Feb 16:19:34 -function timestamp() { - var d = new Date(); - var time = [pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds())].join(':'); - return [d.getDate(), months[d.getMonth()], time].join(' '); -} + // if a drilldown to a specific tile + } else { + // stop tiling if we reached base zoom or our target tile zoom + if (z === options.maxZoom || z === cz) continue; + // stop tiling if it's not an ancestor of the target tile + var m = 1 << (cz - z); + if (x !== Math.floor(cx / m) || y !== Math.floor(cy / m)) continue; + } -// log is just a thin wrapper to console.log that prepends a timestamp -exports.log = function() { - console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); -}; + // stop tiling if the tile is solid clipped square + if (!options.solidChildren && isClippedSquare(tile, options.extent, options.buffer)) { + if (cz) solid = z; // and remember the zoom if we're drilling down + continue; + } + // if we slice further down, no need to keep source geometry + tile.source = null; -/** - * Inherit the prototype methods from one constructor into another. - * - * The Function.prototype.inherits from lang.js rewritten as a standalone - * function (not on Function.prototype). NOTE: If this file is to be loaded - * during bootstrapping this function needs to be rewritten using some native - * functions as prototype setup using normal JavaScript does not work as - * expected during bootstrapping (see mirror.js in r114903). - * - * @param {function} ctor Constructor function which needs to inherit the - * prototype. - * @param {function} superCtor Constructor function to inherit prototype from. - */ -exports.inherits = require('inherits'); + if (debug > 1) console.time('clipping'); -exports._extend = function(origin, add) { - // Don't do anything if add isn't an object - if (!add || !isObject(add)) return origin; + // values we'll use for clipping + var k1 = 0.5 * options.buffer / options.extent, + k2 = 0.5 - k1, + k3 = 0.5 + k1, + k4 = 1 + k1, + tl, bl, tr, br, left, right; - var keys = Object.keys(add); - var i = keys.length; - while (i--) { - origin[keys[i]] = add[keys[i]]; - } - return origin; + tl = bl = tr = br = null; + + left = clip(features, z2, x - k1, x + k3, 0, intersectX, tile.min[0], tile.max[0]); + right = clip(features, z2, x + k2, x + k4, 0, intersectX, tile.min[0], tile.max[0]); + + if (left) { + tl = clip(left, z2, y - k1, y + k3, 1, intersectY, tile.min[1], tile.max[1]); + bl = clip(left, z2, y + k2, y + k4, 1, intersectY, tile.min[1], tile.max[1]); + } + + if (right) { + tr = clip(right, z2, y - k1, y + k3, 1, intersectY, tile.min[1], tile.max[1]); + br = clip(right, z2, y + k2, y + k4, 1, intersectY, tile.min[1], tile.max[1]); + } + + if (debug > 1) console.timeEnd('clipping'); + + if (features.length) { + stack.push(tl || [], z + 1, x * 2, y * 2); + stack.push(bl || [], z + 1, x * 2, y * 2 + 1); + stack.push(tr || [], z + 1, x * 2 + 1, y * 2); + stack.push(br || [], z + 1, x * 2 + 1, y * 2 + 1); + } + } + + return solid; }; -function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -} +GeoJSONVT.prototype.getTile = function (z, x, y) { + var options = this.options, + extent = options.extent, + debug = options.debug; -}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./support/isBuffer":10,"_process":9,"inherits":7}],12:[function(require,module,exports){ -var work = require('webworkify'); -var mapboxgl = require('mapbox-gl'); -var concave = require('turf-concave'); -var geojsonhint = require('geojsonhint'); - -var w = work(require('./worker.js')); -w.addEventListener('message', function(ev) { - console.log(ev.data[0]); - turfResult.setData(ev.data[1]); - -}); -w.addEventListener('error', function(err) { - console.log(err); -}); - -mapboxgl.accessToken = 'pk.eyJ1IjoibnBlaWhsIiwiYSI6InVmU21qeVUifQ.jwa9V6XsmccKsEHKh5QfmQ'; - -var map = new mapboxgl.Map({ - container: 'map', - style: 'mapbox://styles/mapbox/streets-v8', - center: [-122.963104,48.569792], - zoom: 10 -}); - -var dataUrl = 'assets/hydrants.geojson'; - -var hydrants = new mapboxgl.GeoJSONSource({ - data: dataUrl -}); - -var turfResult = new mapboxgl.GeoJSONSource({}); - -map.on('style.load', function() { - console.log('style loaded'); - map.addSource('points', hydrants); - - map.addSource('results', turfResult); - - map.addLayer({ - 'id': 'hydrants', - 'type': 'circle', - 'source': 'points' - }); - - map.addLayer({ - 'id': 'results', - 'type': 'fill', - 'source': 'results', - 'paint': { - 'fill-opacity': 0.6, - 'fill-color': '#00FF00' - } - }); -}); - -map.on('source.load', function() { - console.log('source loaded'); -}); - -addButton('Turf Sync', 'turf-sync'); -addButton('Turf Async','turf-async'); - -function addButton(name, id) { - var link = document.createElement('a'); - link.href = '#'; - link.id = id; - link.className = 'active'; - link.textContent = name; - - link.onclick = function(e) { - e.preventDefault(); - e.stopPropagation(); - - switch (id) { - case 'turf-sync': - turfSync(); - break; - case 'turf-async': - turfAsync(); - break; - } - }; - var menu = document.getElementById('menu'); - menu.appendChild(link); -} - - -function turfSync() { - turfResult.setData(''); - var absUrl = window.location + dataUrl; - makeRequest(absUrl); -} - -function makeRequest(url) { - var req = new XMLHttpRequest(); - req.addEventListener('load', validateData); - req.addEventListener('error', transferFailed); - req.open('GET', url); - req.send(); -} - -function validateData() { - var errors = geojsonhint.hint(this.responseText); - if (errors.len > 0) { - console.log('Errors', errors.join(', ')); - } else { - turfIt(this.responseText); - } -} - -function transferFailed() { - console.log('Error', this.responseText); -} - -function turfIt(data) { - var results = concave(JSON.parse(data), 1, 'miles'); - turfResult.setData(results); -} - -function turfAsync() { - turfResult.setData(''); - var absUrl = window.location + dataUrl; - w.postMessage([absUrl]); -} + var z2 = 1 << z; + x = ((x % z2) + z2) % z2; // wrap tile x coordinate -},{"./worker.js":188,"geojsonhint":13,"mapbox-gl":30,"turf-concave":173,"webworkify":187}],13:[function(require,module,exports){ -var jsonlint = require('jsonlint-lines'), - geojsonHintObject = require('./object'); + var id = toID(z, x, y); + if (this.tiles[id]) return transform.tile(this.tiles[id], extent); -/** - * @alias geojsonhint - * @param {(string|object)} GeoJSON given as a string or as an object - * @param {Object} options - * @param {boolean} [options.noDuplicateMembers=true] forbid repeated - * properties. This is only available for string input, becaused parsed - * Objects cannot have duplicate properties. - * @returns {Array} an array of errors - */ -function hint(str, options) { + if (debug > 1) console.log('drilling down to z%d-%d-%d', z, x, y); - var gj, errors = []; + var z0 = z, + x0 = x, + y0 = y, + parent; - if (typeof str === 'object') { - gj = str; - } else if (typeof str === 'string') { - try { - gj = jsonlint.parse(str); - } catch(e) { - var match = e.message.match(/line (\d+)/), - lineNumber = 0; - if (match) { lineNumber = parseInt(match[1], 10); } - return [{ - line: lineNumber - 1, - message: e.message, - error: e - }]; - } - } else { - return [{ - message: 'Expected string or object as input', - line: 0 - }]; + while (!parent && z0 > 0) { + z0--; + x0 = Math.floor(x0 / 2); + y0 = Math.floor(y0 / 2); + parent = this.tiles[toID(z0, x0, y0)]; } - errors = errors.concat(geojsonHintObject.hint(gj, options)); + if (!parent || !parent.source) return null; - return errors; + // if we found a parent tile containing the original geometry, we can drill down from it + if (debug > 1) console.log('found parent tile z%d-%d-%d', z0, x0, y0); + + // it parent tile is a solid clipped square, return it instead since it's identical + if (isClippedSquare(parent, extent, options.buffer)) return transform.tile(parent, extent); + + if (debug > 1) console.time('drilling down'); + var solid = this.splitTile(parent.source, z0, x0, y0, z, x, y); + if (debug > 1) console.timeEnd('drilling down'); + + // one of the parent tiles was a solid clipped square + if (solid !== null) { + var m = 1 << (z - solid); + id = toID(solid, Math.floor(x / m), Math.floor(y / m)); + } + + return this.tiles[id] ? transform.tile(this.tiles[id], extent) : null; +}; + +function toID(z, x, y) { + return (((1 << z) * y + x) * 32) + z; } -module.exports.hint = hint; +function intersectX(a, b, x) { + return [x, (x - a[0]) * (b[1] - a[1]) / (b[0] - a[0]) + a[1], 1]; +} +function intersectY(a, b, y) { + return [(y - a[1]) * (b[0] - a[0]) / (b[1] - a[1]) + a[0], y, 1]; +} -},{"./object":15,"jsonlint-lines":14}],14:[function(require,module,exports){ -(function (process){ -/* parser generated by jison 0.4.17 */ -/* - Returns a Parser object of the following structure: +function extend(dest, src) { + for (var i in src) dest[i] = src[i]; + return dest; +} - Parser: { - yy: {} - } +// checks whether a tile is a whole-area fill after clipping; if it is, there's no sense slicing it further +function isClippedSquare(tile, extent, buffer) { - Parser.prototype: { - yy: {}, - trace: function(), - symbols_: {associative list: name ==> number}, - terminals_: {associative list: number ==> name}, - productions_: [...], - performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$), - table: [...], - defaultActions: {...}, - parseError: function(str, hash), - parse: function(input), + var features = tile.source; + if (features.length !== 1) return false; - lexer: { - EOF: 1, - parseError: function(str, hash), - setInput: function(input), - input: function(), - unput: function(str), - more: function(), - less: function(n), - pastInput: function(), - upcomingInput: function(), - showPosition: function(), - test_match: function(regex_match_array, rule_index), - next: function(), - lex: function(), - begin: function(condition), - popState: function(), - _currentRules: function(), - topState: function(), - pushState: function(condition), + var feature = features[0]; + if (feature.type !== 3 || feature.geometry.length > 1) return false; - options: { - ranges: boolean (optional: true ==> token location info will include a .range[] member) - flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match) - backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code) - }, + var len = feature.geometry[0].length; + if (len !== 5) return false; - performAction: function(yy, yy_, $avoiding_name_collisions, YY_START), - rules: [...], - conditions: {associative list: name ==> set}, + for (var i = 0; i < len; i++) { + var p = transform.point(feature.geometry[0][i], extent, tile.z2, tile.x, tile.y); + if ((p[0] !== -buffer && p[0] !== extent + buffer) || + (p[1] !== -buffer && p[1] !== extent + buffer)) return false; } - } + return true; +} - token location info (@$, _$, etc.): { - first_line: n, - last_line: n, - first_column: n, - last_column: n, - range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based) - } +},{"./clip":18,"./convert":19,"./tile":23,"./transform":24,"./wrap":25}],22:[function(require,module,exports){ +'use strict'; +module.exports = simplify; - the parseError function receives a 'hash' object with these members for lexer and parser errors: { - text: (matched text) - token: (the produced terminal token, if any) - line: (yylineno) - } - while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: { - loc: (yylloc) - expected: (string describing the set of expected tokens) - recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error) - } -*/ -var jsonlint = (function(){ -var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,12],$V1=[1,13],$V2=[1,9],$V3=[1,10],$V4=[1,11],$V5=[1,14],$V6=[1,15],$V7=[14,18,22,24],$V8=[18,22],$V9=[22,24]; -var parser = {trace: function trace() { }, -yy: {}, -symbols_: {"error":2,"JSONString":3,"STRING":4,"JSONNumber":5,"NUMBER":6,"JSONNullLiteral":7,"NULL":8,"JSONBooleanLiteral":9,"TRUE":10,"FALSE":11,"JSONText":12,"JSONValue":13,"EOF":14,"JSONObject":15,"JSONArray":16,"{":17,"}":18,"JSONMemberList":19,"JSONMember":20,":":21,",":22,"[":23,"]":24,"JSONElementList":25,"$accept":0,"$end":1}, -terminals_: {2:"error",4:"STRING",6:"NUMBER",8:"NULL",10:"TRUE",11:"FALSE",14:"EOF",17:"{",18:"}",21:":",22:",",23:"[",24:"]"}, -productions_: [0,[3,1],[5,1],[7,1],[9,1],[9,1],[12,2],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[15,2],[15,3],[20,3],[19,1],[19,3],[16,2],[16,3],[25,1],[25,3]], -performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { -/* this == yyval */ +// calculate simplification data using optimized Douglas-Peucker algorithm -var $0 = $$.length - 1; -switch (yystate) { -case 1: - // replace escaped characters with actual character - this.$ = yytext.replace(/\\(\\|")/g, "$"+"1") - .replace(/\\n/g,'\n') - .replace(/\\r/g,'\r') - .replace(/\\t/g,'\t') - .replace(/\\v/g,'\v') - .replace(/\\f/g,'\f') - .replace(/\\b/g,'\b'); - -break; -case 2: -this.$ = Number(yytext); -break; -case 3: -this.$ = null; -break; -case 4: -this.$ = true; -break; -case 5: -this.$ = false; -break; -case 6: -return this.$ = $$[$0-1]; -break; -case 13: -this.$ = {}; Object.defineProperty(this.$, '__line__', { - value: this._$.first_line, - enumerable: false - }) -break; -case 14: case 19: -this.$ = $$[$0-1]; Object.defineProperty(this.$, '__line__', { - value: this._$.first_line, - enumerable: false - }) -break; -case 15: -this.$ = [$$[$0-2], $$[$0]]; -break; -case 16: -this.$ = {}; this.$[$$[$0][0]] = $$[$0][1]; -break; -case 17: +function simplify(points, tolerance) { - this.$ = $$[$0-2]; - if ($$[$0-2][$$[$0][0]] !== undefined) { - if (!this.$.__duplicateProperties__) { - Object.defineProperty(this.$, '__duplicateProperties__', { - value: [], - enumerable: false - }); - } - this.$.__duplicateProperties__.push($$[$0][0]); + var sqTolerance = tolerance * tolerance, + len = points.length, + first = 0, + last = len - 1, + stack = [], + i, maxSqDist, sqDist, index; + + // always retain the endpoints (1 is the max value) + points[first][2] = 1; + points[last][2] = 1; + + // avoid recursion by using a stack + while (last) { + + maxSqDist = 0; + + for (i = first + 1; i < last; i++) { + sqDist = getSqSegDist(points[i], points[first], points[last]); + + if (sqDist > maxSqDist) { + index = i; + maxSqDist = sqDist; } - $$[$0-2][$$[$0][0]] = $$[$0][1]; - -break; -case 18: -this.$ = []; Object.defineProperty(this.$, '__line__', { - value: this._$.first_line, - enumerable: false - }) -break; -case 20: -this.$ = [$$[$0]]; -break; -case 21: -this.$ = $$[$0-2]; $$[$0-2].push($$[$0]); -break; -} -}, -table: [{3:5,4:$V0,5:6,6:$V1,7:3,8:$V2,9:4,10:$V3,11:$V4,12:1,13:2,15:7,16:8,17:$V5,23:$V6},{1:[3]},{14:[1,16]},o($V7,[2,7]),o($V7,[2,8]),o($V7,[2,9]),o($V7,[2,10]),o($V7,[2,11]),o($V7,[2,12]),o($V7,[2,3]),o($V7,[2,4]),o($V7,[2,5]),o([14,18,21,22,24],[2,1]),o($V7,[2,2]),{3:20,4:$V0,18:[1,17],19:18,20:19},{3:5,4:$V0,5:6,6:$V1,7:3,8:$V2,9:4,10:$V3,11:$V4,13:23,15:7,16:8,17:$V5,23:$V6,24:[1,21],25:22},{1:[2,6]},o($V7,[2,13]),{18:[1,24],22:[1,25]},o($V8,[2,16]),{21:[1,26]},o($V7,[2,18]),{22:[1,28],24:[1,27]},o($V9,[2,20]),o($V7,[2,14]),{3:20,4:$V0,20:29},{3:5,4:$V0,5:6,6:$V1,7:3,8:$V2,9:4,10:$V3,11:$V4,13:30,15:7,16:8,17:$V5,23:$V6},o($V7,[2,19]),{3:5,4:$V0,5:6,6:$V1,7:3,8:$V2,9:4,10:$V3,11:$V4,13:31,15:7,16:8,17:$V5,23:$V6},o($V8,[2,17]),o($V8,[2,15]),o($V9,[2,21])], -defaultActions: {16:[2,6]}, -parseError: function parseError(str, hash) { - if (hash.recoverable) { - this.trace(str); - } else { - function _parseError (msg, hash) { - this.message = msg; - this.hash = hash; } - _parseError.prototype = Error; - throw new _parseError(str, hash); + if (maxSqDist > sqTolerance) { + points[index][2] = maxSqDist; // save the point importance in squared pixels as a z coordinate + stack.push(first); + stack.push(index); + first = index; + + } else { + last = stack.pop(); + first = stack.pop(); + } } -}, -parse: function parse(input) { - var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; - var args = lstack.slice.call(arguments, 1); - var lexer = Object.create(this.lexer); - var sharedState = { yy: {} }; - for (var k in this.yy) { - if (Object.prototype.hasOwnProperty.call(this.yy, k)) { - sharedState.yy[k] = this.yy[k]; +} + +// square distance from a point to a segment +function getSqSegDist(p, a, b) { + + var x = a[0], y = a[1], + bx = b[0], by = b[1], + px = p[0], py = p[1], + dx = bx - x, + dy = by - y; + + if (dx !== 0 || dy !== 0) { + + var t = ((px - x) * dx + (py - y) * dy) / (dx * dx + dy * dy); + + if (t > 1) { + x = bx; + y = by; + + } else if (t > 0) { + x += dx * t; + y += dy * t; } } - lexer.setInput(input, sharedState.yy); - sharedState.yy.lexer = lexer; - sharedState.yy.parser = this; - if (typeof lexer.yylloc == 'undefined') { - lexer.yylloc = {}; + + dx = px - x; + dy = py - y; + + return dx * dx + dy * dy; +} + +},{}],23:[function(require,module,exports){ +'use strict'; + +module.exports = createTile; + +function createTile(features, z2, tx, ty, tolerance, noSimplify) { + var tile = { + features: [], + numPoints: 0, + numSimplified: 0, + numFeatures: 0, + source: null, + x: tx, + y: ty, + z2: z2, + transformed: false, + min: [2, 1], + max: [-1, 0] + }; + for (var i = 0; i < features.length; i++) { + tile.numFeatures++; + addFeature(tile, features[i], tolerance, noSimplify); + + var min = features[i].min, + max = features[i].max; + + if (min[0] < tile.min[0]) tile.min[0] = min[0]; + if (min[1] < tile.min[1]) tile.min[1] = min[1]; + if (max[0] > tile.max[0]) tile.max[0] = max[0]; + if (max[1] > tile.max[1]) tile.max[1] = max[1]; } - var yyloc = lexer.yylloc; - lstack.push(yyloc); - var ranges = lexer.options && lexer.options.ranges; - if (typeof sharedState.yy.parseError === 'function') { - this.parseError = sharedState.yy.parseError; + return tile; +} + +function addFeature(tile, feature, tolerance, noSimplify) { + + var geom = feature.geometry, + type = feature.type, + simplified = [], + sqTolerance = tolerance * tolerance, + i, j, ring, p; + + if (type === 1) { + for (i = 0; i < geom.length; i++) { + simplified.push(geom[i]); + tile.numPoints++; + tile.numSimplified++; + } + } else { - this.parseError = Object.getPrototypeOf(this).parseError; - } - function popStack(n) { - stack.length = stack.length - 2 * n; - vstack.length = vstack.length - n; - lstack.length = lstack.length - n; - } - _token_stack: - var lex = function () { - var token; - token = lexer.lex() || EOF; - if (typeof token !== 'number') { - token = self.symbols_[token] || token; - } - return token; - }; - var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected; - while (true) { - state = stack[stack.length - 1]; - if (this.defaultActions[state]) { - action = this.defaultActions[state]; - } else { - if (symbol === null || typeof symbol == 'undefined') { - symbol = lex(); + + // simplify and transform projected coordinates for tile geometry + for (i = 0; i < geom.length; i++) { + ring = geom[i]; + + // filter out tiny polylines & polygons + if (!noSimplify && ((type === 2 && ring.dist < tolerance) || + (type === 3 && ring.area < sqTolerance))) { + tile.numPoints += ring.length; + continue; } - action = table[state] && table[state][symbol]; - } - if (typeof action === 'undefined' || !action.length || !action[0]) { - var errStr = ''; - expected = []; - for (p in table[state]) { - if (this.terminals_[p] && p > TERROR) { - expected.push('\'' + this.terminals_[p] + '\''); - } - } - if (lexer.showPosition) { - errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\''; - } else { - errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\''); + + var simplifiedRing = []; + + for (j = 0; j < ring.length; j++) { + p = ring[j]; + // keep points with importance > tolerance + if (noSimplify || p[2] > sqTolerance) { + simplifiedRing.push(p); + tile.numSimplified++; } - this.parseError(errStr, { - text: lexer.match, - token: this.terminals_[symbol] || symbol, - line: lexer.yylineno, - loc: yyloc, - expected: expected - }); + tile.numPoints++; } - if (action[0] instanceof Array && action.length > 1) { - throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol); + + if (type === 3) rewind(simplifiedRing, ring.outer); + + simplified.push(simplifiedRing); } - switch (action[0]) { - case 1: - stack.push(symbol); - vstack.push(lexer.yytext); - lstack.push(lexer.yylloc); - stack.push(action[1]); - symbol = null; - if (!preErrorSymbol) { - yyleng = lexer.yyleng; - yytext = lexer.yytext; - yylineno = lexer.yylineno; - yyloc = lexer.yylloc; - if (recovering > 0) { - recovering--; - } - } else { - symbol = preErrorSymbol; - preErrorSymbol = null; - } - break; - case 2: - len = this.productions_[action[1]][1]; - yyval.$ = vstack[vstack.length - len]; - yyval._$ = { - first_line: lstack[lstack.length - (len || 1)].first_line, - last_line: lstack[lstack.length - 1].last_line, - first_column: lstack[lstack.length - (len || 1)].first_column, - last_column: lstack[lstack.length - 1].last_column - }; - if (ranges) { - yyval._$.range = [ - lstack[lstack.length - (len || 1)].range[0], - lstack[lstack.length - 1].range[1] - ]; - } - r = this.performAction.apply(yyval, [ - yytext, - yyleng, - yylineno, - sharedState.yy, - action[1], - vstack, - lstack - ].concat(args)); - if (typeof r !== 'undefined') { - return r; - } - if (len) { - stack = stack.slice(0, -1 * len * 2); - vstack = vstack.slice(0, -1 * len); - lstack = lstack.slice(0, -1 * len); - } - stack.push(this.productions_[action[1]][0]); - vstack.push(yyval.$); - lstack.push(yyval._$); - newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; - stack.push(newState); - break; - case 3: - return true; + } + + if (simplified.length) { + var tileFeature = { + geometry: simplified, + type: type, + tags: feature.tags || null + }; + if (feature.id !== null) { + tileFeature.id = feature.id; } + tile.features.push(tileFeature); } - return true; -}}; -/* generated by jison-lex 0.3.4 */ -var lexer = (function(){ -var lexer = ({ +} -EOF:1, +function rewind(ring, clockwise) { + var area = signedArea(ring); + if (area < 0 === clockwise) ring.reverse(); +} -parseError:function parseError(str, hash) { - if (this.yy.parser) { - this.yy.parser.parseError(str, hash); - } else { - throw new Error(str); - } - }, +function signedArea(ring) { + var sum = 0; + for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) { + p1 = ring[i]; + p2 = ring[j]; + sum += (p2[0] - p1[0]) * (p1[1] + p2[1]); + } + return sum; +} -// resets the lexer, sets new input -setInput:function (input, yy) { - this.yy = yy || this.yy || {}; - this._input = input; - this._more = this._backtrack = this.done = false; - this.yylineno = this.yyleng = 0; - this.yytext = this.matched = this.match = ''; - this.conditionStack = ['INITIAL']; - this.yylloc = { - first_line: 1, - first_column: 0, - last_line: 1, - last_column: 0 - }; - if (this.options.ranges) { - this.yylloc.range = [0,0]; - } - this.offset = 0; - return this; - }, +},{}],24:[function(require,module,exports){ +'use strict'; + +exports.tile = transformTile; +exports.point = transformPoint; + +// Transforms the coordinates of each feature in the given tile from +// mercator-projected space into (extent x extent) tile space. +function transformTile(tile, extent) { + if (tile.transformed) return tile; + + var z2 = tile.z2, + tx = tile.x, + ty = tile.y, + i, j, k; + + for (i = 0; i < tile.features.length; i++) { + var feature = tile.features[i], + geom = feature.geometry, + type = feature.type; + + if (type === 1) { + for (j = 0; j < geom.length; j++) geom[j] = transformPoint(geom[j], extent, z2, tx, ty); -// consumes and returns one char from the input -input:function () { - var ch = this._input[0]; - this.yytext += ch; - this.yyleng++; - this.offset++; - this.match += ch; - this.matched += ch; - var lines = ch.match(/(?:\r\n?|\n).*/g); - if (lines) { - this.yylineno++; - this.yylloc.last_line++; } else { - this.yylloc.last_column++; - } - if (this.options.ranges) { - this.yylloc.range[1]++; + for (j = 0; j < geom.length; j++) { + var ring = geom[j]; + for (k = 0; k < ring.length; k++) ring[k] = transformPoint(ring[k], extent, z2, tx, ty); + } } + } - this._input = this._input.slice(1); - return ch; - }, + tile.transformed = true; -// unshifts one char (or a string) into the input -unput:function (ch) { - var len = ch.length; - var lines = ch.split(/(?:\r\n?|\n)/g); + return tile; +} - this._input = ch + this._input; - this.yytext = this.yytext.substr(0, this.yytext.length - len); - //this.yyleng -= len; - this.offset -= len; - var oldLines = this.match.split(/(?:\r\n?|\n)/g); - this.match = this.match.substr(0, this.match.length - 1); - this.matched = this.matched.substr(0, this.matched.length - 1); +function transformPoint(p, extent, z2, tx, ty) { + var x = Math.round(extent * (p[0] * z2 - tx)), + y = Math.round(extent * (p[1] * z2 - ty)); + return [x, y]; +} - if (lines.length - 1) { - this.yylineno -= lines.length - 1; - } - var r = this.yylloc.range; +},{}],25:[function(require,module,exports){ +'use strict'; - this.yylloc = { - first_line: this.yylloc.first_line, - last_line: this.yylineno + 1, - first_column: this.yylloc.first_column, - last_column: lines ? - (lines.length === oldLines.length ? this.yylloc.first_column : 0) - + oldLines[oldLines.length - lines.length].length - lines[0].length : - this.yylloc.first_column - len - }; +var clip = require('./clip'); +var createFeature = require('./feature'); - if (this.options.ranges) { - this.yylloc.range = [r[0], r[0] + this.yyleng - len]; - } - this.yyleng = this.yytext.length; - return this; - }, +module.exports = wrap; -// When called from action, caches matched text and appends it on next action -more:function () { - this._more = true; - return this; - }, +function wrap(features, buffer, intersectX) { + var merged = features, + left = clip(features, 1, -1 - buffer, buffer, 0, intersectX, -1, 2), // left world copy + right = clip(features, 1, 1 - buffer, 2 + buffer, 0, intersectX, -1, 2); // right world copy -// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead. -reject:function () { - if (this.options.backtrack_lexer) { - this._backtrack = true; - } else { - return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), { - text: "", - token: null, - line: this.yylineno - }); + if (left || right) { + merged = clip(features, 1, -buffer, 1 + buffer, 0, intersectX, -1, 2) || []; // center world copy - } - return this; - }, + if (left) merged = shiftFeatureCoords(left, 1).concat(merged); // merge left into center + if (right) merged = merged.concat(shiftFeatureCoords(right, -1)); // merge right into center + } -// retain first n characters of the match -less:function (n) { - this.unput(this.match.slice(n)); - }, + return merged; +} -// displays already matched input, i.e. for error messages -pastInput:function () { - var past = this.matched.substr(0, this.matched.length - this.match.length); - return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); - }, +function shiftFeatureCoords(features, offset) { + var newFeatures = []; -// displays upcoming input, i.e. for error messages -upcomingInput:function () { - var next = this.match; - if (next.length < 20) { - next += this._input.substr(0, 20-next.length); + for (var i = 0; i < features.length; i++) { + var feature = features[i], + type = feature.type; + + var newGeometry; + + if (type === 1) { + newGeometry = shiftCoords(feature.geometry, offset); + } else { + newGeometry = []; + for (var j = 0; j < feature.geometry.length; j++) { + newGeometry.push(shiftCoords(feature.geometry[j], offset)); + } } - return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, ""); - }, -// displays the character position where the lexing error occurred, i.e. for error messages -showPosition:function () { - var pre = this.pastInput(); - var c = new Array(pre.length + 1).join("-"); - return pre + this.upcomingInput() + "\n" + c + "^"; - }, + newFeatures.push(createFeature(feature.tags, type, newGeometry, feature.id)); + } -// test the lexed token: return FALSE when not a match, otherwise return token -test_match:function (match, indexed_rule) { - var token, - lines, - backup; + return newFeatures; +} - if (this.options.backtrack_lexer) { - // save context - backup = { - yylineno: this.yylineno, - yylloc: { - first_line: this.yylloc.first_line, - last_line: this.last_line, - first_column: this.yylloc.first_column, - last_column: this.yylloc.last_column - }, - yytext: this.yytext, - match: this.match, - matches: this.matches, - matched: this.matched, - yyleng: this.yyleng, - offset: this.offset, - _more: this._more, - _input: this._input, - yy: this.yy, - conditionStack: this.conditionStack.slice(0), - done: this.done - }; - if (this.options.ranges) { - backup.yylloc.range = this.yylloc.range.slice(0); - } - } - - lines = match[0].match(/(?:\r\n?|\n).*/g); - if (lines) { - this.yylineno += lines.length; - } - this.yylloc = { - first_line: this.yylloc.last_line, - last_line: this.yylineno + 1, - first_column: this.yylloc.last_column, - last_column: lines ? - lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : - this.yylloc.last_column + match[0].length - }; - this.yytext += match[0]; - this.match += match[0]; - this.matches = match; - this.yyleng = this.yytext.length; - if (this.options.ranges) { - this.yylloc.range = [this.offset, this.offset += this.yyleng]; - } - this._more = false; - this._backtrack = false; - this._input = this._input.slice(match[0].length); - this.matched += match[0]; - token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]); - if (this.done && this._input) { - this.done = false; - } - if (token) { - return token; - } else if (this._backtrack) { - // recover context - for (var k in backup) { - this[k] = backup[k]; - } - return false; // rule action called reject() implying the next rule should be tested instead. - } - return false; - }, - -// return next match in input -next:function () { - if (this.done) { - return this.EOF; - } - if (!this._input) { - this.done = true; - } - - var token, - match, - tempMatch, - index; - if (!this._more) { - this.yytext = ''; - this.match = ''; - } - var rules = this._currentRules(); - for (var i = 0; i < rules.length; i++) { - tempMatch = this._input.match(this.rules[rules[i]]); - if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { - match = tempMatch; - index = i; - if (this.options.backtrack_lexer) { - token = this.test_match(tempMatch, rules[i]); - if (token !== false) { - return token; - } else if (this._backtrack) { - match = false; - continue; // rule action called reject() implying a rule MISmatch. - } else { - // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) - return false; - } - } else if (!this.options.flex) { - break; - } - } - } - if (match) { - token = this.test_match(match, rules[index]); - if (token !== false) { - return token; - } - // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) - return false; - } - if (this._input === "") { - return this.EOF; - } else { - return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { - text: "", - token: null, - line: this.yylineno - }); - } - }, - -// return next match that has a token -lex:function lex() { - var r = this.next(); - if (r) { - return r; - } else { - return this.lex(); - } - }, - -// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack) -begin:function begin(condition) { - this.conditionStack.push(condition); - }, - -// pop the previously active lexer condition state off the condition stack -popState:function popState() { - var n = this.conditionStack.length - 1; - if (n > 0) { - return this.conditionStack.pop(); - } else { - return this.conditionStack[0]; - } - }, - -// produce the lexer rule set which is active for the currently active lexer condition state -_currentRules:function _currentRules() { - if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) { - return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules; - } else { - return this.conditions["INITIAL"].rules; - } - }, - -// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available -topState:function topState(n) { - n = this.conditionStack.length - 1 - Math.abs(n || 0); - if (n >= 0) { - return this.conditionStack[n]; - } else { - return "INITIAL"; - } - }, - -// alias for begin(condition) -pushState:function pushState(condition) { - this.begin(condition); - }, +function shiftCoords(points, offset) { + var newPoints = []; + newPoints.area = points.area; + newPoints.dist = points.dist; -// return the number of states currently on the stack -stateStackSize:function stateStackSize() { - return this.conditionStack.length; - }, -options: {}, -performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { -var YYSTATE=YY_START; -switch($avoiding_name_collisions) { -case 0:/* skip whitespace */ -break; -case 1:return 6 -break; -case 2:yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2); return 4 -break; -case 3:return 17 -break; -case 4:return 18 -break; -case 5:return 23 -break; -case 6:return 24 -break; -case 7:return 22 -break; -case 8:return 21 -break; -case 9:return 10 -break; -case 10:return 11 -break; -case 11:return 8 -break; -case 12:return 14 -break; -case 13:return 'INVALID' -break; -} -}, -rules: [/^(?:\s+)/,/^(?:(-?([0-9]|[1-9][0-9]+))(\.[0-9]+)?([eE][-+]?[0-9]+)?\b)/,/^(?:"(?:\\[\\"bfnrt\/]|\\u[a-fA-F0-9]{4}|[^\\\0-\x09\x0a-\x1f"])*")/,/^(?:\{)/,/^(?:\})/,/^(?:\[)/,/^(?:\])/,/^(?:,)/,/^(?::)/,/^(?:true\b)/,/^(?:false\b)/,/^(?:null\b)/,/^(?:$)/,/^(?:.)/], -conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13],"inclusive":true}} -}); -return lexer; -})(); -parser.lexer = lexer; -function Parser () { - this.yy = {}; + for (var i = 0; i < points.length; i++) { + newPoints.push([points[i][0] + offset, points[i][1], points[i][2]]); + } + return newPoints; } -Parser.prototype = parser;parser.Parser = Parser; -return new Parser; -})(); +},{"./clip":18,"./feature":20}],26:[function(require,module,exports){ +var jsonlint = require('jsonlint-lines'), + geojsonHintObject = require('./object'); -if (typeof require !== 'undefined' && typeof exports !== 'undefined') { -exports.parser = jsonlint; -exports.Parser = jsonlint.Parser; -exports.parse = function () { return jsonlint.parse.apply(jsonlint, arguments); }; -exports.main = function commonjsMain(args) { - if (!args[1]) { - console.log('Usage: '+args[0]+' FILE'); - process.exit(1); - } - var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8"); - return exports.parser.parse(source); -}; -if (typeof module !== 'undefined' && require.main === module) { - exports.main(process.argv.slice(1)); -} -} -}).call(this,require('_process')) -},{"_process":9,"fs":1,"path":8}],15:[function(require,module,exports){ /** * @alias geojsonhint * @param {(string|object)} GeoJSON given as a string or as an object @@ -3879,25680 +3385,28735 @@ if (typeof module !== 'undefined' && require.main === module) { * Objects cannot have duplicate properties. * @returns {Array} an array of errors */ -function hint(gj, options) { - - var errors = []; +function hint(str, options) { - function root(_) { + var gj, errors = []; - if ((!options || options.noDuplicateMembers !== false) && - _.__duplicateProperties__) { - errors.push({ - message: 'An object contained duplicate members, making parsing ambigous: ' + _.__duplicateProperties__.join(', '), - line: _.__line__ - }); - } - - if (!_.type) { - errors.push({ - message: 'The type property is required and was not found', - line: _.__line__ - }); - } else if (!types[_.type]) { - errors.push({ - message: 'The type ' + _.type + ' is unknown', - line: _.__line__ - }); - } else if (_) { - types[_.type](_); + if (typeof str === 'object') { + gj = str; + } else if (typeof str === 'string') { + try { + gj = jsonlint.parse(str); + } catch(e) { + var match = e.message.match(/line (\d+)/), + lineNumber = 0; + if (match) { lineNumber = parseInt(match[1], 10); } + return [{ + line: lineNumber - 1, + message: e.message, + error: e + }]; } + } else { + return [{ + message: 'Expected string or object as input', + line: 0 + }]; } - function everyIs(_, type) { - // make a single exception because typeof null === 'object' - return _.every(function(x) { return (x !== null) && (typeof x === type); }); - } + errors = errors.concat(geojsonHintObject.hint(gj, options)); - function requiredProperty(_, name, type) { - if (typeof _[name] === 'undefined') { - return errors.push({ - message: '"' + name + '" property required', - line: _.__line__ - }); - } else if (type === 'array') { - if (!Array.isArray(_[name])) { - return errors.push({ - message: '"' + name + - '" property should be an array, but is an ' + - (typeof _[name]) + ' instead', - line: _.__line__ - }); - } - } else if (type && typeof _[name] !== type) { - return errors.push({ - message: '"' + name + - '" property should be ' + (type) + - ', but is an ' + (typeof _[name]) + ' instead', - line: _.__line__ - }); - } - } + return errors; +} - // http://geojson.org/geojson-spec.html#feature-collection-objects - function FeatureCollection(featureCollection) { - crs(featureCollection); - bbox(featureCollection); - if (!requiredProperty(featureCollection, 'features', 'array')) { - if (!everyIs(featureCollection.features, 'object')) { - return errors.push({ - message: 'Every feature must be an object', - line: featureCollection.__line__ - }); - } - featureCollection.features.forEach(Feature); - } - } +module.exports.hint = hint; - // http://geojson.org/geojson-spec.html#positions - function position(_, line) { - if (!Array.isArray(_)) { - return errors.push({ - message: 'position should be an array, is a ' + (typeof _) + - ' instead', - line: _.__line__ || line - }); - } else { - if (_.length < 2) { - return errors.push({ - message: 'position must have 2 or more elements', - line: _.__line__ || line - }); - } - if (!everyIs(_, 'number')) { - return errors.push({ - message: 'each element in a position must be a number', - line: _.__line__ || line - }); - } - } - } +},{"./object":28,"jsonlint-lines":27}],27:[function(require,module,exports){ +(function (process){ +/* parser generated by jison 0.4.17 */ +/* + Returns a Parser object of the following structure: - function positionArray(coords, type, depth, line) { - if (line === undefined && coords.__line__ !== undefined) { - line = coords.__line__; - } - if (depth === 0) { - return position(coords, line); - } else { - if (depth === 1 && type) { - if (type === 'LinearRing') { - if (!Array.isArray(coords[coords.length - 1])) { - return errors.push({ - message: 'a number was found where a coordinate array should have been found: this needs to be nested more deeply', - line: line - }); - } - if (coords.length < 4) { - errors.push({ - message: 'a LinearRing of coordinates needs to have four or more positions', - line: line - }); - } - if (coords.length && - (coords[coords.length - 1].length !== coords[0].length || - !coords[coords.length - 1].every(function(position, index) { - return coords[0][index] === position; - }))) { - errors.push({ - message: 'the first and last positions in a LinearRing of coordinates must be the same', - line: line - }); - } - } else if (type === 'Line' && coords.length < 2) { - errors.push({ - message: 'a line needs to have two or more coordinates to be valid', - line: line - }); - } - } - coords.forEach(function(c) { - positionArray(c, type, depth - 1, c.__line__ || line); - }); - } - } + Parser: { + yy: {} + } - function crs(_) { - if (!_.crs) return; - if (typeof _.crs === 'object') { - var strErr = requiredProperty(_.crs, 'type', 'string'), - propErr = requiredProperty(_.crs, 'properties', 'object'); - if (!strErr && !propErr) { - // http://geojson.org/geojson-spec.html#named-crs - if (_.crs.type === 'name') { - requiredProperty(_.crs.properties, 'name', 'string'); - } else if (_.crs.type === 'link') { - requiredProperty(_.crs.properties, 'href', 'string'); - } - } - } else { - errors.push({ - message: 'the value of the crs property must be an object, not a ' + (typeof _.crs), - line: _.__line__ - }); - } - } + Parser.prototype: { + yy: {}, + trace: function(), + symbols_: {associative list: name ==> number}, + terminals_: {associative list: number ==> name}, + productions_: [...], + performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$), + table: [...], + defaultActions: {...}, + parseError: function(str, hash), + parse: function(input), - function bbox(_) { - if (!_.bbox) { return; } - if (Array.isArray(_.bbox)) { - if (!everyIs(_.bbox, 'number')) { - return errors.push({ - message: 'each element in a bbox property must be a number', - line: _.bbox.__line__ - }); - } - } else { - errors.push({ - message: 'bbox property must be an array of numbers, but is a ' + (typeof _.bbox), - line: _.__line__ - }); - } - } + lexer: { + EOF: 1, + parseError: function(str, hash), + setInput: function(input), + input: function(), + unput: function(str), + more: function(), + less: function(n), + pastInput: function(), + upcomingInput: function(), + showPosition: function(), + test_match: function(regex_match_array, rule_index), + next: function(), + lex: function(), + begin: function(condition), + popState: function(), + _currentRules: function(), + topState: function(), + pushState: function(condition), - // http://geojson.org/geojson-spec.html#point - function Point(point) { - crs(point); - bbox(point); - if (!requiredProperty(point, 'coordinates', 'array')) { - position(point.coordinates); - } - } + options: { + ranges: boolean (optional: true ==> token location info will include a .range[] member) + flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match) + backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code) + }, - // http://geojson.org/geojson-spec.html#polygon - function Polygon(polygon) { - crs(polygon); - bbox(polygon); - if (!requiredProperty(polygon, 'coordinates', 'array')) { - positionArray(polygon.coordinates, 'LinearRing', 2); - } + performAction: function(yy, yy_, $avoiding_name_collisions, YY_START), + rules: [...], + conditions: {associative list: name ==> set}, } + } - // http://geojson.org/geojson-spec.html#multipolygon - function MultiPolygon(multiPolygon) { - crs(multiPolygon); - bbox(multiPolygon); - if (!requiredProperty(multiPolygon, 'coordinates', 'array')) { - positionArray(multiPolygon.coordinates, 'LinearRing', 3); - } - } - // http://geojson.org/geojson-spec.html#linestring - function LineString(lineString) { - crs(lineString); - bbox(lineString); - if (!requiredProperty(lineString, 'coordinates', 'array')) { - positionArray(lineString.coordinates, 'Line', 1); - } - } + token location info (@$, _$, etc.): { + first_line: n, + last_line: n, + first_column: n, + last_column: n, + range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based) + } - // http://geojson.org/geojson-spec.html#multilinestring - function MultiLineString(multiLineString) { - crs(multiLineString); - bbox(multiLineString); - if (!requiredProperty(multiLineString, 'coordinates', 'array')) { - positionArray(multiLineString.coordinates, 'Line', 2); - } - } - // http://geojson.org/geojson-spec.html#multipoint - function MultiPoint(multiPoint) { - crs(multiPoint); - bbox(multiPoint); - if (!requiredProperty(multiPoint, 'coordinates', 'array')) { - positionArray(multiPoint.coordinates, '', 1); - } - } + the parseError function receives a 'hash' object with these members for lexer and parser errors: { + text: (matched text) + token: (the produced terminal token, if any) + line: (yylineno) + } + while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: { + loc: (yylloc) + expected: (string describing the set of expected tokens) + recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error) + } +*/ +var jsonlint = (function(){ +var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,12],$V1=[1,13],$V2=[1,9],$V3=[1,10],$V4=[1,11],$V5=[1,14],$V6=[1,15],$V7=[14,18,22,24],$V8=[18,22],$V9=[22,24]; +var parser = {trace: function trace() { }, +yy: {}, +symbols_: {"error":2,"JSONString":3,"STRING":4,"JSONNumber":5,"NUMBER":6,"JSONNullLiteral":7,"NULL":8,"JSONBooleanLiteral":9,"TRUE":10,"FALSE":11,"JSONText":12,"JSONValue":13,"EOF":14,"JSONObject":15,"JSONArray":16,"{":17,"}":18,"JSONMemberList":19,"JSONMember":20,":":21,",":22,"[":23,"]":24,"JSONElementList":25,"$accept":0,"$end":1}, +terminals_: {2:"error",4:"STRING",6:"NUMBER",8:"NULL",10:"TRUE",11:"FALSE",14:"EOF",17:"{",18:"}",21:":",22:",",23:"[",24:"]"}, +productions_: [0,[3,1],[5,1],[7,1],[9,1],[9,1],[12,2],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[15,2],[15,3],[20,3],[19,1],[19,3],[16,2],[16,3],[25,1],[25,3]], +performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { +/* this == yyval */ - function GeometryCollection(geometryCollection) { - crs(geometryCollection); - bbox(geometryCollection); - if (!requiredProperty(geometryCollection, 'geometries', 'array')) { - geometryCollection.geometries.forEach(function(geometry) { - if (geometry) root(geometry); - }); - } - } +var $0 = $$.length - 1; +switch (yystate) { +case 1: + // replace escaped characters with actual character + this.$ = yytext.replace(/\\(\\|")/g, "$"+"1") + .replace(/\\n/g,'\n') + .replace(/\\r/g,'\r') + .replace(/\\t/g,'\t') + .replace(/\\v/g,'\v') + .replace(/\\f/g,'\f') + .replace(/\\b/g,'\b'); + +break; +case 2: +this.$ = Number(yytext); +break; +case 3: +this.$ = null; +break; +case 4: +this.$ = true; +break; +case 5: +this.$ = false; +break; +case 6: +return this.$ = $$[$0-1]; +break; +case 13: +this.$ = {}; Object.defineProperty(this.$, '__line__', { + value: this._$.first_line, + enumerable: false + }) +break; +case 14: case 19: +this.$ = $$[$0-1]; Object.defineProperty(this.$, '__line__', { + value: this._$.first_line, + enumerable: false + }) +break; +case 15: +this.$ = [$$[$0-2], $$[$0]]; +break; +case 16: +this.$ = {}; this.$[$$[$0][0]] = $$[$0][1]; +break; +case 17: - function Feature(feature) { - crs(feature); - bbox(feature); - // https://github.com/geojson/draft-geojson/blob/master/middle.mkd#feature-object - if (feature.id !== undefined && - typeof feature.id !== 'string' && - typeof feature.id !== 'number') { - errors.push({ - message: 'Feature "id" property must have a string or number value', - line: feature.__line__ - }); - } - if (feature.type !== 'Feature') { - errors.push({ - message: 'GeoJSON features must have a type=feature property', - line: feature.__line__ - }); - } - requiredProperty(feature, 'properties', 'object'); - if (!requiredProperty(feature, 'geometry', 'object')) { - // http://geojson.org/geojson-spec.html#feature-objects - // tolerate null geometry - if (feature.geometry) root(feature.geometry); + this.$ = $$[$0-2]; + if ($$[$0-2][$$[$0][0]] !== undefined) { + if (!this.$.__duplicateProperties__) { + Object.defineProperty(this.$, '__duplicateProperties__', { + value: [], + enumerable: false + }); + } + this.$.__duplicateProperties__.push($$[$0][0]); + } + $$[$0-2][$$[$0][0]] = $$[$0][1]; + +break; +case 18: +this.$ = []; Object.defineProperty(this.$, '__line__', { + value: this._$.first_line, + enumerable: false + }) +break; +case 20: +this.$ = [$$[$0]]; +break; +case 21: +this.$ = $$[$0-2]; $$[$0-2].push($$[$0]); +break; +} +}, +table: [{3:5,4:$V0,5:6,6:$V1,7:3,8:$V2,9:4,10:$V3,11:$V4,12:1,13:2,15:7,16:8,17:$V5,23:$V6},{1:[3]},{14:[1,16]},o($V7,[2,7]),o($V7,[2,8]),o($V7,[2,9]),o($V7,[2,10]),o($V7,[2,11]),o($V7,[2,12]),o($V7,[2,3]),o($V7,[2,4]),o($V7,[2,5]),o([14,18,21,22,24],[2,1]),o($V7,[2,2]),{3:20,4:$V0,18:[1,17],19:18,20:19},{3:5,4:$V0,5:6,6:$V1,7:3,8:$V2,9:4,10:$V3,11:$V4,13:23,15:7,16:8,17:$V5,23:$V6,24:[1,21],25:22},{1:[2,6]},o($V7,[2,13]),{18:[1,24],22:[1,25]},o($V8,[2,16]),{21:[1,26]},o($V7,[2,18]),{22:[1,28],24:[1,27]},o($V9,[2,20]),o($V7,[2,14]),{3:20,4:$V0,20:29},{3:5,4:$V0,5:6,6:$V1,7:3,8:$V2,9:4,10:$V3,11:$V4,13:30,15:7,16:8,17:$V5,23:$V6},o($V7,[2,19]),{3:5,4:$V0,5:6,6:$V1,7:3,8:$V2,9:4,10:$V3,11:$V4,13:31,15:7,16:8,17:$V5,23:$V6},o($V8,[2,17]),o($V8,[2,15]),o($V9,[2,21])], +defaultActions: {16:[2,6]}, +parseError: function parseError(str, hash) { + if (hash.recoverable) { + this.trace(str); + } else { + function _parseError (msg, hash) { + this.message = msg; + this.hash = hash; } - } - - var types = { - Point: Point, - Feature: Feature, - MultiPoint: MultiPoint, - LineString: LineString, - MultiLineString: MultiLineString, - FeatureCollection: FeatureCollection, - GeometryCollection: GeometryCollection, - Polygon: Polygon, - MultiPolygon: MultiPolygon - }; + _parseError.prototype = Error; - if (typeof gj !== 'object' || - gj === null || - gj === undefined) { - errors.push({ - message: 'The root of a GeoJSON object must be an object.', - line: 0 - }); - return errors; + throw new _parseError(str, hash); } - - root(gj); - - errors.forEach(function(err) { - if (err.hasOwnProperty('line') && err.line === undefined) { - delete err.line; +}, +parse: function parse(input) { + var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; + var args = lstack.slice.call(arguments, 1); + var lexer = Object.create(this.lexer); + var sharedState = { yy: {} }; + for (var k in this.yy) { + if (Object.prototype.hasOwnProperty.call(this.yy, k)) { + sharedState.yy[k] = this.yy[k]; } - }); - - return errors; -} - -module.exports.hint = hint; - -},{}],16:[function(require,module,exports){ -'use strict'; - -var featureFilter = require('feature-filter'); - -var ElementGroups = require('./element_groups'); -var Buffer = require('./buffer'); -var StyleLayer = require('../style/style_layer'); - -module.exports = Bucket; - -/** - * Instantiate the appropriate subclass of `Bucket` for `options`. - * @private - * @param options See `Bucket` constructor options - * @returns {Bucket} - */ -Bucket.create = function(options) { - var Classes = { - fill: require('./fill_bucket'), - line: require('./line_bucket'), - circle: require('./circle_bucket'), - symbol: require('./symbol_bucket') - }; - return new Classes[options.layer.type](options); -}; - -Bucket.AttributeType = Buffer.AttributeType; - -/** - * The `Bucket` class builds a set of `Buffer`s for a set of vector tile - * features. - * - * `Bucket` is an abstract class. A subclass exists for each Mapbox GL - * style spec layer type. Because `Bucket` is an abstract class, - * instances should be created via the `Bucket.create` method. - * - * For performance reasons, `Bucket` creates its "add"s methods at - * runtime using `new Function(...)`. - * - * @class Bucket - * @private - * @param options - * @param {number} options.zoom Zoom level of the buffers being built. May be - * a fractional zoom level. - * @param options.layer A Mapbox GL style layer object - * @param {Object.} options.buffers The set of `Buffer`s being - * built for this tile. This object facilitates sharing of `Buffer`s be - between `Bucket`s. - */ -function Bucket(options) { - this.zoom = options.zoom; - - this.layer = StyleLayer.create(options.layer); - this.layer.recalculate(this.zoom, { lastIntegerZoom: Infinity, lastIntegerZoomTime: 0, lastZoom: 0 }); - - this.layers = [this.layer.id]; - this.type = this.layer.type; - this.features = []; - this.id = this.layer.id; - this['source-layer'] = this.layer['source-layer']; - this.interactive = this.layer.interactive; - this.minZoom = this.layer.minzoom; - this.maxZoom = this.layer.maxzoom; - this.filter = featureFilter(this.layer.filter); - - this.resetBuffers(options.buffers); - - for (var shaderName in this.shaders) { - var shader = this.shaders[shaderName]; - this[this.getAddMethodName(shaderName, 'vertex')] = createVertexAddMethod( - shaderName, - shader, - this.getBufferName(shaderName, 'vertex') - ); } -} - -/** - * Build the buffers! Features are set directly to the `features` property. - * @private - */ -Bucket.prototype.addFeatures = function() { - for (var i = 0; i < this.features.length; i++) { - this.addFeature(this.features[i]); + lexer.setInput(input, sharedState.yy); + sharedState.yy.lexer = lexer; + sharedState.yy.parser = this; + if (typeof lexer.yylloc == 'undefined') { + lexer.yylloc = {}; } -}; - -/** - * Check if there is enough space available in the current element group for - * `vertexLength` vertices. If not, append a new elementGroup. Should be called - * by `addFeatures` and its callees. - * @private - * @param {string} shaderName the name of the shader associated with the buffer that will receive the vertices - * @param {number} vertexLength The number of vertices that will be inserted to the buffer. - */ -Bucket.prototype.makeRoomFor = function(shaderName, vertexLength) { - return this.elementGroups[shaderName].makeRoomFor(vertexLength); -}; - -/** - * Start using a new shared `buffers` object and recreate instances of `Buffer` - * as necessary. - * @private - * @param {Object.} buffers - */ -Bucket.prototype.resetBuffers = function(buffers) { - this.buffers = buffers; - this.elementGroups = {}; - - for (var shaderName in this.shaders) { - var shader = this.shaders[shaderName]; - - var vertexBufferName = this.getBufferName(shaderName, 'vertex'); - if (shader.vertexBuffer && !buffers[vertexBufferName]) { - buffers[vertexBufferName] = new Buffer({ - type: Buffer.BufferType.VERTEX, - attributes: shader.attributes - }); + var yyloc = lexer.yylloc; + lstack.push(yyloc); + var ranges = lexer.options && lexer.options.ranges; + if (typeof sharedState.yy.parseError === 'function') { + this.parseError = sharedState.yy.parseError; + } else { + this.parseError = Object.getPrototypeOf(this).parseError; + } + function popStack(n) { + stack.length = stack.length - 2 * n; + vstack.length = vstack.length - n; + lstack.length = lstack.length - n; + } + _token_stack: + var lex = function () { + var token; + token = lexer.lex() || EOF; + if (typeof token !== 'number') { + token = self.symbols_[token] || token; + } + return token; + }; + var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected; + while (true) { + state = stack[stack.length - 1]; + if (this.defaultActions[state]) { + action = this.defaultActions[state]; + } else { + if (symbol === null || typeof symbol == 'undefined') { + symbol = lex(); + } + action = table[state] && table[state][symbol]; } - - if (shader.elementBuffer) { - var elementBufferName = this.getBufferName(shaderName, 'element'); - if (!buffers[elementBufferName]) { - buffers[elementBufferName] = createElementBuffer(shader.elementBufferComponents); + if (typeof action === 'undefined' || !action.length || !action[0]) { + var errStr = ''; + expected = []; + for (p in table[state]) { + if (this.terminals_[p] && p > TERROR) { + expected.push('\'' + this.terminals_[p] + '\''); + } + } + if (lexer.showPosition) { + errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\''; + } else { + errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\''); + } + this.parseError(errStr, { + text: lexer.match, + token: this.terminals_[symbol] || symbol, + line: lexer.yylineno, + loc: yyloc, + expected: expected + }); } - this[this.getAddMethodName(shaderName, 'element')] = createElementAddMethod(this.buffers[elementBufferName]); + if (action[0] instanceof Array && action.length > 1) { + throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol); } - - if (shader.secondElementBuffer) { - var secondElementBufferName = this.getBufferName(shaderName, 'secondElement'); - if (!buffers[secondElementBufferName]) { - buffers[secondElementBufferName] = createElementBuffer(shader.secondElementBufferComponents); + switch (action[0]) { + case 1: + stack.push(symbol); + vstack.push(lexer.yytext); + lstack.push(lexer.yylloc); + stack.push(action[1]); + symbol = null; + if (!preErrorSymbol) { + yyleng = lexer.yyleng; + yytext = lexer.yytext; + yylineno = lexer.yylineno; + yyloc = lexer.yylloc; + if (recovering > 0) { + recovering--; + } + } else { + symbol = preErrorSymbol; + preErrorSymbol = null; + } + break; + case 2: + len = this.productions_[action[1]][1]; + yyval.$ = vstack[vstack.length - len]; + yyval._$ = { + first_line: lstack[lstack.length - (len || 1)].first_line, + last_line: lstack[lstack.length - 1].last_line, + first_column: lstack[lstack.length - (len || 1)].first_column, + last_column: lstack[lstack.length - 1].last_column + }; + if (ranges) { + yyval._$.range = [ + lstack[lstack.length - (len || 1)].range[0], + lstack[lstack.length - 1].range[1] + ]; + } + r = this.performAction.apply(yyval, [ + yytext, + yyleng, + yylineno, + sharedState.yy, + action[1], + vstack, + lstack + ].concat(args)); + if (typeof r !== 'undefined') { + return r; + } + if (len) { + stack = stack.slice(0, -1 * len * 2); + vstack = vstack.slice(0, -1 * len); + lstack = lstack.slice(0, -1 * len); } - this[this.getAddMethodName(shaderName, 'secondElement')] = createElementAddMethod(this.buffers[secondElementBufferName]); + stack.push(this.productions_[action[1]][0]); + vstack.push(yyval.$); + lstack.push(yyval._$); + newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; + stack.push(newState); + break; + case 3: + return true; } - - this.elementGroups[shaderName] = new ElementGroups( - buffers[this.getBufferName(shaderName, 'vertex')], - buffers[this.getBufferName(shaderName, 'element')], - buffers[this.getBufferName(shaderName, 'secondElement')] - ); - } -}; - -/** - * Get the name of the method used to add an item to a buffer. - * @param {string} shaderName The name of the shader that will use the buffer - * @param {string} type One of "vertex", "element", or "secondElement" - * @returns {string} - */ -Bucket.prototype.getAddMethodName = function(shaderName, type) { - return 'add' + capitalize(shaderName) + capitalize(type); -}; - -/** - * Get the name of a buffer. - * @param {string} shaderName The name of the shader that will use the buffer - * @param {string} type One of "vertex", "element", or "secondElement" - * @returns {string} - */ -Bucket.prototype.getBufferName = function(shaderName, type) { - return shaderName + capitalize(type); -}; - -var createVertexAddMethodCache = {}; -function createVertexAddMethod(shaderName, shader, bufferName) { - var pushArgs = []; - for (var i = 0; i < shader.attributes.length; i++) { - pushArgs = pushArgs.concat(shader.attributes[i].value); } + return true; +}}; +/* generated by jison-lex 0.3.4 */ +var lexer = (function(){ +var lexer = ({ - var body = 'return this.buffers.' + bufferName + '.push(' + pushArgs.join(', ') + ');'; +EOF:1, - if (!createVertexAddMethodCache[body]) { - createVertexAddMethodCache[body] = new Function(shader.attributeArgs, body); - } +parseError:function parseError(str, hash) { + if (this.yy.parser) { + this.yy.parser.parseError(str, hash); + } else { + throw new Error(str); + } + }, - return createVertexAddMethodCache[body]; -} +// resets the lexer, sets new input +setInput:function (input, yy) { + this.yy = yy || this.yy || {}; + this._input = input; + this._more = this._backtrack = this.done = false; + this.yylineno = this.yyleng = 0; + this.yytext = this.matched = this.match = ''; + this.conditionStack = ['INITIAL']; + this.yylloc = { + first_line: 1, + first_column: 0, + last_line: 1, + last_column: 0 + }; + if (this.options.ranges) { + this.yylloc.range = [0,0]; + } + this.offset = 0; + return this; + }, -function createElementAddMethod(buffer) { - return function(one, two, three) { - return buffer.push(one, two, three); - }; -} +// consumes and returns one char from the input +input:function () { + var ch = this._input[0]; + this.yytext += ch; + this.yyleng++; + this.offset++; + this.match += ch; + this.matched += ch; + var lines = ch.match(/(?:\r\n?|\n).*/g); + if (lines) { + this.yylineno++; + this.yylloc.last_line++; + } else { + this.yylloc.last_column++; + } + if (this.options.ranges) { + this.yylloc.range[1]++; + } -function createElementBuffer(components) { - return new Buffer({ - type: Buffer.BufferType.ELEMENT, - attributes: [{ - name: 'vertices', - components: components || 3, - type: Buffer.ELEMENT_ATTRIBUTE_TYPE - }] - }); -} + this._input = this._input.slice(1); + return ch; + }, -function capitalize(string) { - return string.charAt(0).toUpperCase() + string.slice(1); -} +// unshifts one char (or a string) into the input +unput:function (ch) { + var len = ch.length; + var lines = ch.split(/(?:\r\n?|\n)/g); -},{"../style/style_layer":63,"./buffer":17,"./circle_bucket":18,"./element_groups":19,"./fill_bucket":21,"./line_bucket":22,"./symbol_bucket":24,"feature-filter":115}],17:[function(require,module,exports){ -'use strict'; + this._input = ch + this._input; + this.yytext = this.yytext.substr(0, this.yytext.length - len); + //this.yyleng -= len; + this.offset -= len; + var oldLines = this.match.split(/(?:\r\n?|\n)/g); + this.match = this.match.substr(0, this.match.length - 1); + this.matched = this.matched.substr(0, this.matched.length - 1); -// Note: all "sizes" are measured in bytes + if (lines.length - 1) { + this.yylineno -= lines.length - 1; + } + var r = this.yylloc.range; -var assert = require('assert'); + this.yylloc = { + first_line: this.yylloc.first_line, + last_line: this.yylineno + 1, + first_column: this.yylloc.first_column, + last_column: lines ? + (lines.length === oldLines.length ? this.yylloc.first_column : 0) + + oldLines[oldLines.length - lines.length].length - lines[0].length : + this.yylloc.first_column - len + }; -/** - * The `Buffer` class is responsible for managing one instance of `ArrayBuffer`. `ArrayBuffer`s - * provide low-level read/write access to a chunk of memory. `ArrayBuffer`s are populated with - * per-vertex data, uploaded to the GPU, and used in rendering. - * - * `Buffer` provides an abstraction over `ArrayBuffer`, making it behave like an array of - * statically typed structs. A buffer is comprised of items. An item is comprised of a set of - * attributes. Attributes are defined when the class is constructed. - * - * @class Buffer - * @private - * @param options - * @param {BufferType} options.type - * @param {Array.} options.attributes - */ -function Buffer(options) { + if (this.options.ranges) { + this.yylloc.range = [r[0], r[0] + this.yyleng - len]; + } + this.yyleng = this.yytext.length; + return this; + }, - this.type = options.type; +// When called from action, caches matched text and appends it on next action +more:function () { + this._more = true; + return this; + }, - // Clone an existing Buffer - if (options.arrayBuffer) { +// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead. +reject:function () { + if (this.options.backtrack_lexer) { + this._backtrack = true; + } else { + return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), { + text: "", + token: null, + line: this.yylineno + }); - this.capacity = options.capacity; - this.arrayBuffer = options.arrayBuffer; - this.attributes = options.attributes; - this.itemSize = options.itemSize; - this.length = options.length; + } + return this; + }, - // Create a new Buffer - } else { - - this.capacity = align(Buffer.CAPACITY_DEFAULT, Buffer.CAPACITY_ALIGNMENT); - this.arrayBuffer = new ArrayBuffer(this.capacity); - this.attributes = []; - this.itemSize = 0; - this.length = 0; - - // Vertex buffer attributes must be aligned to word boundaries but - // element buffer attributes do not need to be aligned. - var attributeAlignment = this.type === Buffer.BufferType.VERTEX ? Buffer.VERTEX_ATTRIBUTE_ALIGNMENT : 1; - - this.attributes = options.attributes.map(function(attributeOptions) { - var attribute = {}; - - attribute.name = attributeOptions.name; - attribute.components = attributeOptions.components || 1; - attribute.type = attributeOptions.type || Buffer.AttributeType.UNSIGNED_BYTE; - attribute.size = attribute.type.size * attribute.components; - attribute.offset = this.itemSize; - - this.itemSize = align(attribute.offset + attribute.size, attributeAlignment); - - assert(!isNaN(this.itemSize)); - assert(!isNaN(attribute.size)); - assert(attribute.type.name in Buffer.AttributeType); - - return attribute; - }, this); - - // These are expensive calls. Because we only push things to buffers in - // the worker thread, we can skip in the "clone an existing buffer" case. - this._createPushMethod(); - this._refreshViews(); - } -} - -/** - * Bind this buffer to a WebGL context. - * @private - * @param gl The WebGL context - */ -Buffer.prototype.bind = function(gl) { - var type = gl[this.type]; - - if (!this.buffer) { - this.buffer = gl.createBuffer(); - gl.bindBuffer(type, this.buffer); - gl.bufferData(type, this.arrayBuffer.slice(0, this.length * this.itemSize), gl.STATIC_DRAW); - - // dump array buffer once it's bound to gl - this.arrayBuffer = null; - } else { - gl.bindBuffer(type, this.buffer); - } -}; - -/** - * Destroy the GL buffer bound to the given WebGL context - * @private - * @param gl The WebGL context - */ -Buffer.prototype.destroy = function(gl) { - if (this.buffer) { - gl.deleteBuffer(this.buffer); - } -}; - -/** - * Set the attribute pointers in a WebGL context according to the buffer's attribute layout - * @private - * @param gl The WebGL context - * @param shader The active WebGL shader - * @param {number} offset The offset of the attribute data in the currently bound GL buffer. - */ -Buffer.prototype.setAttribPointers = function(gl, shader, offset) { - for (var i = 0; i < this.attributes.length; i++) { - var attrib = this.attributes[i]; +// retain first n characters of the match +less:function (n) { + this.unput(this.match.slice(n)); + }, - gl.vertexAttribPointer( - shader['a_' + attrib.name], attrib.components, gl[attrib.type.name], - false, this.itemSize, offset + attrib.offset); - } -}; +// displays already matched input, i.e. for error messages +pastInput:function () { + var past = this.matched.substr(0, this.matched.length - this.match.length); + return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); + }, -/** - * Get an item from the `ArrayBuffer`. Only used for debugging. - * @private - * @param {number} index The index of the item to get - * @returns {Object.>} - */ -Buffer.prototype.get = function(index) { - this._refreshViews(); +// displays upcoming input, i.e. for error messages +upcomingInput:function () { + var next = this.match; + if (next.length < 20) { + next += this._input.substr(0, 20-next.length); + } + return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, ""); + }, - var item = {}; - var offset = index * this.itemSize; +// displays the character position where the lexing error occurred, i.e. for error messages +showPosition:function () { + var pre = this.pastInput(); + var c = new Array(pre.length + 1).join("-"); + return pre + this.upcomingInput() + "\n" + c + "^"; + }, - for (var i = 0; i < this.attributes.length; i++) { - var attribute = this.attributes[i]; - var values = item[attribute.name] = []; +// test the lexed token: return FALSE when not a match, otherwise return token +test_match:function (match, indexed_rule) { + var token, + lines, + backup; - for (var j = 0; j < attribute.components; j++) { - var componentOffset = ((offset + attribute.offset) / attribute.type.size) + j; - values.push(this.views[attribute.type.name][componentOffset]); + if (this.options.backtrack_lexer) { + // save context + backup = { + yylineno: this.yylineno, + yylloc: { + first_line: this.yylloc.first_line, + last_line: this.last_line, + first_column: this.yylloc.first_column, + last_column: this.yylloc.last_column + }, + yytext: this.yytext, + match: this.match, + matches: this.matches, + matched: this.matched, + yyleng: this.yyleng, + offset: this.offset, + _more: this._more, + _input: this._input, + yy: this.yy, + conditionStack: this.conditionStack.slice(0), + done: this.done + }; + if (this.options.ranges) { + backup.yylloc.range = this.yylloc.range.slice(0); + } } - } - return item; -}; -/** - * Check that a buffer item is well formed and throw an error if not. Only - * used for debugging. - * @private - * @param {number} args The "arguments" object from Buffer::push - */ -Buffer.prototype.validate = function(args) { - var argIndex = 0; - for (var i = 0; i < this.attributes.length; i++) { - for (var j = 0; j < this.attributes[i].components; j++) { - assert(!isNaN(args[argIndex++])); + lines = match[0].match(/(?:\r\n?|\n).*/g); + if (lines) { + this.yylineno += lines.length; } - } - assert(argIndex === args.length); -}; - -Buffer.prototype._resize = function(capacity) { - var old = this.views.UNSIGNED_BYTE; - this.capacity = align(capacity, Buffer.CAPACITY_ALIGNMENT); - this.arrayBuffer = new ArrayBuffer(this.capacity); - this._refreshViews(); - this.views.UNSIGNED_BYTE.set(old); -}; - -Buffer.prototype._refreshViews = function() { - this.views = { - UNSIGNED_BYTE: new Uint8Array(this.arrayBuffer), - BYTE: new Int8Array(this.arrayBuffer), - UNSIGNED_SHORT: new Uint16Array(this.arrayBuffer), - SHORT: new Int16Array(this.arrayBuffer) - }; -}; + this.yylloc = { + first_line: this.yylloc.last_line, + last_line: this.yylineno + 1, + first_column: this.yylloc.last_column, + last_column: lines ? + lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : + this.yylloc.last_column + match[0].length + }; + this.yytext += match[0]; + this.match += match[0]; + this.matches = match; + this.yyleng = this.yytext.length; + if (this.options.ranges) { + this.yylloc.range = [this.offset, this.offset += this.yyleng]; + } + this._more = false; + this._backtrack = false; + this._input = this._input.slice(match[0].length); + this.matched += match[0]; + token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]); + if (this.done && this._input) { + this.done = false; + } + if (token) { + return token; + } else if (this._backtrack) { + // recover context + for (var k in backup) { + this[k] = backup[k]; + } + return false; // rule action called reject() implying the next rule should be tested instead. + } + return false; + }, -var createPushMethodCache = {}; -Buffer.prototype._createPushMethod = function() { - var body = ''; - var argNames = []; +// return next match in input +next:function () { + if (this.done) { + return this.EOF; + } + if (!this._input) { + this.done = true; + } - body += 'var i = this.length++;\n'; - body += 'var o = i * ' + this.itemSize + ';\n'; - body += 'if (o + ' + this.itemSize + ' > this.capacity) { this._resize(this.capacity * 1.5); }\n'; + var token, + match, + tempMatch, + index; + if (!this._more) { + this.yytext = ''; + this.match = ''; + } + var rules = this._currentRules(); + for (var i = 0; i < rules.length; i++) { + tempMatch = this._input.match(this.rules[rules[i]]); + if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { + match = tempMatch; + index = i; + if (this.options.backtrack_lexer) { + token = this.test_match(tempMatch, rules[i]); + if (token !== false) { + return token; + } else if (this._backtrack) { + match = false; + continue; // rule action called reject() implying a rule MISmatch. + } else { + // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) + return false; + } + } else if (!this.options.flex) { + break; + } + } + } + if (match) { + token = this.test_match(match, rules[index]); + if (token !== false) { + return token; + } + // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) + return false; + } + if (this._input === "") { + return this.EOF; + } else { + return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { + text: "", + token: null, + line: this.yylineno + }); + } + }, - for (var i = 0; i < this.attributes.length; i++) { - var attribute = this.attributes[i]; - var offsetId = 'o' + i; +// return next match that has a token +lex:function lex() { + var r = this.next(); + if (r) { + return r; + } else { + return this.lex(); + } + }, - body += '\nvar ' + offsetId + ' = (o + ' + attribute.offset + ') / ' + attribute.type.size + ';\n'; +// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack) +begin:function begin(condition) { + this.conditionStack.push(condition); + }, - for (var j = 0; j < attribute.components; j++) { - var rvalue = 'v' + argNames.length; - var lvalue = 'this.views.' + attribute.type.name + '[' + offsetId + ' + ' + j + ']'; - body += lvalue + ' = ' + rvalue + ';\n'; - argNames.push(rvalue); +// pop the previously active lexer condition state off the condition stack +popState:function popState() { + var n = this.conditionStack.length - 1; + if (n > 0) { + return this.conditionStack.pop(); + } else { + return this.conditionStack[0]; } - } - - body += '\nreturn i;\n'; + }, - if (!createPushMethodCache[body]) { - createPushMethodCache[body] = new Function(argNames, body); - } +// produce the lexer rule set which is active for the currently active lexer condition state +_currentRules:function _currentRules() { + if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) { + return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules; + } else { + return this.conditions["INITIAL"].rules; + } + }, - this.push = createPushMethodCache[body]; -}; +// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available +topState:function topState(n) { + n = this.conditionStack.length - 1 - Math.abs(n || 0); + if (n >= 0) { + return this.conditionStack[n]; + } else { + return "INITIAL"; + } + }, -/** - * @typedef BufferAttribute - * @private - * @property {string} name - * @property {number} components - * @property {BufferAttributeType} type - * @property {number} size - * @property {number} offset - */ +// alias for begin(condition) +pushState:function pushState(condition) { + this.begin(condition); + }, -/** - * @enum {string} BufferType - * @private - * @readonly - */ -Buffer.BufferType = { - VERTEX: 'ARRAY_BUFFER', - ELEMENT: 'ELEMENT_ARRAY_BUFFER' -}; - -/** - * @enum {{size: number, name: string}} BufferAttributeType - * @private - * @readonly - */ -Buffer.AttributeType = { - BYTE: { size: 1, name: 'BYTE' }, - UNSIGNED_BYTE: { size: 1, name: 'UNSIGNED_BYTE' }, - SHORT: { size: 2, name: 'SHORT' }, - UNSIGNED_SHORT: { size: 2, name: 'UNSIGNED_SHORT' } -}; - -/** - * An `BufferType.ELEMENT` buffer holds indicies of a corresponding `BufferType.VERTEX` buffer. - * These indicies are stored in the `BufferType.ELEMENT` buffer as `UNSIGNED_SHORT`s. - * - * @property {BufferAttributeType} - * @private - * @readonly - */ -Buffer.ELEMENT_ATTRIBUTE_TYPE = Buffer.AttributeType.UNSIGNED_SHORT; - -/** - * The maximum extent of a feature that can be safely stored in the buffer. - * In practice, all features are converted to this extent before being added. - * - * Positions are stored as signed 16bit integers. - * One bit is lost for signedness to support featuers extending past the left edge of the tile. - * One bit is lost because the line vertex buffer packs 1 bit of other data into the int. - * One bit is lost to support features extending past the extent on the right edge of the tile. - * This leaves us with 2^13 = 8192 - * - * @property {number} - * @private - * @readonly - */ -Buffer.EXTENT = 8192; - -/** - * @property {number} - * @private - * @readonly - */ -Buffer.CAPACITY_DEFAULT = 8192; - -/** - * WebGL performs best if buffer sizes are aligned to 2 byte boundaries. - * @property {number} - * @private - * @readonly - */ -Buffer.CAPACITY_ALIGNMENT = 2; - -/** - * WebGL performs best if vertex attribute offsets are aligned to 4 byte boundaries. - * @property {number} - * @private - * @readonly - */ -Buffer.VERTEX_ATTRIBUTE_ALIGNMENT = 4; - -function align(value, alignment) { - alignment = alignment || 1; - var remainder = value % alignment; - if (alignment !== 1 && remainder !== 0) { - value += (alignment - remainder); - } - return value; +// return the number of states currently on the stack +stateStackSize:function stateStackSize() { + return this.conditionStack.length; + }, +options: {}, +performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { +var YYSTATE=YY_START; +switch($avoiding_name_collisions) { +case 0:/* skip whitespace */ +break; +case 1:return 6 +break; +case 2:yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2); return 4 +break; +case 3:return 17 +break; +case 4:return 18 +break; +case 5:return 23 +break; +case 6:return 24 +break; +case 7:return 22 +break; +case 8:return 21 +break; +case 9:return 10 +break; +case 10:return 11 +break; +case 11:return 8 +break; +case 12:return 14 +break; +case 13:return 'INVALID' +break; } - -module.exports = Buffer; - -},{"assert":2}],18:[function(require,module,exports){ -'use strict'; - -var Bucket = require('./bucket'); -var util = require('../util/util'); -var loadGeometry = require('./load_geometry'); -var EXTENT = require('./buffer').EXTENT; - -module.exports = CircleBucket; - -/** - * Circles are represented by two triangles. - * - * Each corner has a pos that is the center of the circle and an extrusion - * vector that is where it points. - * @private - */ -function CircleBucket() { - Bucket.apply(this, arguments); +}, +rules: [/^(?:\s+)/,/^(?:(-?([0-9]|[1-9][0-9]+))(\.[0-9]+)?([eE][-+]?[0-9]+)?\b)/,/^(?:"(?:\\[\\"bfnrt\/]|\\u[a-fA-F0-9]{4}|[^\\\0-\x09\x0a-\x1f"])*")/,/^(?:\{)/,/^(?:\})/,/^(?:\[)/,/^(?:\])/,/^(?:,)/,/^(?::)/,/^(?:true\b)/,/^(?:false\b)/,/^(?:null\b)/,/^(?:$)/,/^(?:.)/], +conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13],"inclusive":true}} +}); +return lexer; +})(); +parser.lexer = lexer; +function Parser () { + this.yy = {}; } +Parser.prototype = parser;parser.Parser = Parser; +return new Parser; +})(); -CircleBucket.prototype = util.inherit(Bucket, {}); - -CircleBucket.prototype.shaders = { - circle: { - vertexBuffer: true, - elementBuffer: true, - - attributeArgs: ['x', 'y', 'extrudeX', 'extrudeY'], - - attributes: [{ - name: 'pos', - components: 2, - type: Bucket.AttributeType.SHORT, - value: [ - '(x * 2) + ((extrudeX + 1) / 2)', - '(y * 2) + ((extrudeY + 1) / 2)' - ] - }] - } -}; - -CircleBucket.prototype.addFeature = function(feature) { - - var geometries = loadGeometry(feature); - for (var j = 0; j < geometries.length; j++) { - var geometry = geometries[j]; - - for (var k = 0; k < geometry.length; k++) { - var group = this.makeRoomFor('circle', 4); - - var x = geometry[k].x; - var y = geometry[k].y; - - // Do not include points that are outside the tile boundaries. - if (x < 0 || x >= EXTENT || y < 0 || y >= EXTENT) continue; - - // this geometry will be of the Point type, and we'll derive - // two triangles from it. - // - // ┌─────────┐ - // │ 3 2 │ - // │ │ - // │ 0 1 │ - // └─────────┘ - - var index = this.addCircleVertex(x, y, -1, -1) - group.vertexStartIndex; - this.addCircleVertex(x, y, 1, -1); - this.addCircleVertex(x, y, 1, 1); - this.addCircleVertex(x, y, -1, 1); - group.vertexLength += 4; - - this.addCircleElement(index, index + 1, index + 2); - this.addCircleElement(index, index + 3, index + 2); - group.elementLength += 2; - } - } - -}; - -},{"../util/util":113,"./bucket":16,"./buffer":17,"./load_geometry":23}],19:[function(require,module,exports){ -'use strict'; - -module.exports = ElementGroups; - -function ElementGroups(vertexBuffer, elementBuffer, secondElementBuffer) { - - this.vertexBuffer = vertexBuffer; - this.elementBuffer = elementBuffer; - this.secondElementBuffer = secondElementBuffer; - this.groups = []; -} -ElementGroups.prototype.makeRoomFor = function(numVertices) { - if (!this.current || this.current.vertexLength + numVertices > 65535) { - this.current = new ElementGroup(this.vertexBuffer.length, - this.elementBuffer && this.elementBuffer.length, - this.secondElementBuffer && this.secondElementBuffer.length); - this.groups.push(this.current); +if (typeof require !== 'undefined' && typeof exports !== 'undefined') { +exports.parser = jsonlint; +exports.Parser = jsonlint.Parser; +exports.parse = function () { return jsonlint.parse.apply(jsonlint, arguments); }; +exports.main = function commonjsMain(args) { + if (!args[1]) { + console.log('Usage: '+args[0]+' FILE'); + process.exit(1); } - return this.current; + var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8"); + return exports.parser.parse(source); }; - -function ElementGroup(vertexStartIndex, elementStartIndex, secondElementStartIndex) { - // the offset into the vertex buffer of the first vertex in this group - this.vertexStartIndex = vertexStartIndex; - this.elementStartIndex = elementStartIndex; - this.secondElementStartIndex = secondElementStartIndex; - this.elementLength = 0; - this.vertexLength = 0; - this.secondElementLength = 0; +if (typeof module !== 'undefined' && require.main === module) { + exports.main(process.argv.slice(1)); } - -},{}],20:[function(require,module,exports){ -'use strict'; - -var rbush = require('rbush'); -var Point = require('point-geometry'); -var vt = require('vector-tile'); -var util = require('../util/util'); -var loadGeometry = require('./load_geometry'); -var EXTENT = require('./buffer').EXTENT; - -module.exports = FeatureTree; - -function FeatureTree(coord, overscaling) { - this.x = coord.x; - this.y = coord.y; - this.z = coord.z - Math.log(overscaling) / Math.LN2; - this.rtree = rbush(9); - this.toBeInserted = []; } +}).call(this,require('_process')) +},{"_process":197,"fs":9,"path":194}],28:[function(require,module,exports){ +/** + * @alias geojsonhint + * @param {(string|object)} GeoJSON given as a string or as an object + * @param {Object} options + * @param {boolean} [options.noDuplicateMembers=true] forbid repeated + * properties. This is only available for string input, becaused parsed + * Objects cannot have duplicate properties. + * @returns {Array} an array of errors + */ +function hint(gj, options) { -FeatureTree.prototype.insert = function(bbox, layers, feature) { - var scale = EXTENT / feature.extent; - bbox[0] *= scale; - bbox[1] *= scale; - bbox[2] *= scale; - bbox[3] *= scale; - bbox.layers = layers; - bbox.feature = feature; - this.toBeInserted.push(bbox); -}; - -// bulk insert into tree -FeatureTree.prototype._load = function() { - this.rtree.load(this.toBeInserted); - this.toBeInserted = []; -}; - -// Finds features in this tile at a particular position. -FeatureTree.prototype.query = function(args, callback) { - if (this.toBeInserted.length) this._load(); - - var params = args.params || {}, - x = args.x, - y = args.y, - result = []; - - var radius, bounds; - if (typeof x !== 'undefined' && typeof y !== 'undefined') { - // a point (or point+radius) query - radius = (params.radius || 0) * EXTENT / args.scale; - bounds = [x - radius, y - radius, x + radius, y + radius]; - } else { - // a rectangle query - bounds = [ args.minX, args.minY, args.maxX, args.maxY ]; - } - - var matching = this.rtree.search(bounds); - for (var i = 0; i < matching.length; i++) { - var feature = matching[i].feature, - layers = matching[i].layers, - type = vt.VectorTileFeature.types[feature.type]; - - if (params.$type && type !== params.$type) - continue; - if (radius && !geometryContainsPoint(loadGeometry(feature), type, new Point(x, y), radius)) - continue; - else if (!geometryIntersectsBox(loadGeometry(feature), type, bounds)) - continue; + var errors = []; - var geoJSON = feature.toGeoJSON(this.x, this.y, this.z); + function root(_) { - if (!params.includeGeometry) { - geoJSON.geometry = null; + if ((!options || options.noDuplicateMembers !== false) && + _.__duplicateProperties__) { + errors.push({ + message: 'An object contained duplicate members, making parsing ambigous: ' + _.__duplicateProperties__.join(', '), + line: _.__line__ + }); } - for (var l = 0; l < layers.length; l++) { - var layer = layers[l]; - - if (params.layerIds && params.layerIds.indexOf(layer) < 0) - continue; - - result.push(util.extend({layer: layer}, geoJSON)); + if (!_.type) { + errors.push({ + message: 'The type property is required and was not found', + line: _.__line__ + }); + } else if (!types[_.type]) { + errors.push({ + message: 'The type ' + _.type + ' is unknown', + line: _.__line__ + }); + } else if (_) { + types[_.type](_); } } - callback(null, result); -}; - -function geometryIntersectsBox(rings, type, bounds) { - return type === 'Point' ? pointIntersectsBox(rings, bounds) : - type === 'LineString' ? lineIntersectsBox(rings, bounds) : - type === 'Polygon' ? polyIntersectsBox(rings, bounds) || lineIntersectsBox(rings, bounds) : false; -} - -// Tests whether any of the four corners of the bbox are contained in the -// interior of the polygon. Otherwise, defers to lineIntersectsBox. -function polyIntersectsBox(rings, bounds) { - if (polyContainsPoint(rings, new Point(bounds[0], bounds[1])) || - polyContainsPoint(rings, new Point(bounds[0], bounds[3])) || - polyContainsPoint(rings, new Point(bounds[2], bounds[1])) || - polyContainsPoint(rings, new Point(bounds[2], bounds[3]))) - return true; - return lineIntersectsBox(rings, bounds); -} + function everyIs(_, type) { + // make a single exception because typeof null === 'object' + return _.every(function(x) { return (x !== null) && (typeof x === type); }); + } -// Only needs to cover the case where the line crosses the bbox boundary. -// Otherwise, pointIntersectsBox should have us covered. -function lineIntersectsBox(rings, bounds) { - for (var k = 0; k < rings.length; k++) { - var ring = rings[k]; - for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) { - var p0 = ring[i]; - var p1 = ring[j]; - - // invert the segment so as to reuse segmentCrossesHorizontal for - // checking whether it crosses the vertical sides of the bbox. - var i0 = new Point(p0.y, p0.x); - var i1 = new Point(p1.y, p1.x); - - if (segmentCrossesHorizontal(p0, p1, bounds[0], bounds[2], bounds[1]) || - segmentCrossesHorizontal(p0, p1, bounds[0], bounds[2], bounds[3]) || - segmentCrossesHorizontal(i0, i1, bounds[1], bounds[3], bounds[0]) || - segmentCrossesHorizontal(i0, i1, bounds[1], bounds[3], bounds[2])) - return true; + function requiredProperty(_, name, type) { + if (typeof _[name] === 'undefined') { + return errors.push({ + message: '"' + name + '" property required', + line: _.__line__ + }); + } else if (type === 'array') { + if (!Array.isArray(_[name])) { + return errors.push({ + message: '"' + name + + '" property should be an array, but is an ' + + (typeof _[name]) + ' instead', + line: _.__line__ + }); + } + } else if (type && typeof _[name] !== type) { + return errors.push({ + message: '"' + name + + '" property should be ' + (type) + + ', but is an ' + (typeof _[name]) + ' instead', + line: _.__line__ + }); } } - return pointIntersectsBox(rings, bounds); -} - -/* - * Answer whether segment p1-p2 intersects with (x1, y)-(x2, y) - * Assumes x2 >= x1 - */ -function segmentCrossesHorizontal(p0, p1, x1, x2, y) { - if (p1.y === p0.y) - return p1.y === y && - Math.min(p0.x, p1.x) <= x2 && - Math.max(p0.x, p1.x) >= x1; - - var r = (y - p0.y) / (p1.y - p0.y); - var x = p0.x + r * (p1.x - p0.x); - return (x >= x1 && x <= x2 && r <= 1 && r >= 0); -} - -function pointIntersectsBox(rings, bounds) { - for (var i = 0; i < rings.length; i++) { - var ring = rings[i]; - for (var j = 0; j < ring.length; j++) { - if (ring[j].x >= bounds[0] && - ring[j].y >= bounds[1] && - ring[j].x <= bounds[2] && - ring[j].y <= bounds[3]) return true; + // http://geojson.org/geojson-spec.html#feature-collection-objects + function FeatureCollection(featureCollection) { + crs(featureCollection); + bbox(featureCollection); + if (!requiredProperty(featureCollection, 'features', 'array')) { + if (!everyIs(featureCollection.features, 'object')) { + return errors.push({ + message: 'Every feature must be an object', + line: featureCollection.__line__ + }); + } + featureCollection.features.forEach(Feature); } } - return false; -} -function geometryContainsPoint(rings, type, p, radius) { - return type === 'Point' ? pointContainsPoint(rings, p, radius) : - type === 'LineString' ? lineContainsPoint(rings, p, radius) : - type === 'Polygon' ? polyContainsPoint(rings, p) || lineContainsPoint(rings, p, radius) : false; -} - -// Code from http://stackoverflow.com/a/1501725/331379. -function distToSegmentSquared(p, v, w) { - var l2 = v.distSqr(w); - if (l2 === 0) return p.distSqr(v); - var t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2; - if (t < 0) return p.distSqr(v); - if (t > 1) return p.distSqr(w); - return p.distSqr(w.sub(v)._mult(t)._add(v)); -} - -function lineContainsPoint(rings, p, radius) { - var r = radius * radius; - - for (var i = 0; i < rings.length; i++) { - var ring = rings[i]; - for (var j = 1; j < ring.length; j++) { - // Find line segments that have a distance <= radius^2 to p - // In that case, we treat the line as "containing point p". - var v = ring[j - 1], w = ring[j]; - if (distToSegmentSquared(p, v, w) < r) return true; + // http://geojson.org/geojson-spec.html#positions + function position(_, line) { + if (!Array.isArray(_)) { + return errors.push({ + message: 'position should be an array, is a ' + (typeof _) + + ' instead', + line: _.__line__ || line + }); + } else { + if (_.length < 2) { + return errors.push({ + message: 'position must have 2 or more elements', + line: _.__line__ || line + }); + } + if (!everyIs(_, 'number')) { + return errors.push({ + message: 'each element in a position must be a number', + line: _.__line__ || line + }); + } } } - return false; -} -// point in polygon ray casting algorithm -function polyContainsPoint(rings, p) { - var c = false, - ring, p1, p2; - - for (var k = 0; k < rings.length; k++) { - ring = rings[k]; - for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) { - p1 = ring[i]; - p2 = ring[j]; - if (((p1.y > p.y) !== (p2.y > p.y)) && (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) { - c = !c; + function positionArray(coords, type, depth, line) { + if (line === undefined && coords.__line__ !== undefined) { + line = coords.__line__; + } + if (depth === 0) { + return position(coords, line); + } else { + if (depth === 1 && type) { + if (type === 'LinearRing') { + if (!Array.isArray(coords[coords.length - 1])) { + return errors.push({ + message: 'a number was found where a coordinate array should have been found: this needs to be nested more deeply', + line: line + }); + } + if (coords.length < 4) { + errors.push({ + message: 'a LinearRing of coordinates needs to have four or more positions', + line: line + }); + } + if (coords.length && + (coords[coords.length - 1].length !== coords[0].length || + !coords[coords.length - 1].every(function(position, index) { + return coords[0][index] === position; + }))) { + errors.push({ + message: 'the first and last positions in a LinearRing of coordinates must be the same', + line: line + }); + } + } else if (type === 'Line' && coords.length < 2) { + errors.push({ + message: 'a line needs to have two or more coordinates to be valid', + line: line + }); + } } + coords.forEach(function(c) { + positionArray(c, type, depth - 1, c.__line__ || line); + }); } } - return c; -} - -function pointContainsPoint(rings, p, radius) { - var r = radius * radius; - for (var i = 0; i < rings.length; i++) { - var ring = rings[i]; - for (var j = 0; j < ring.length; j++) { - if (ring[j].distSqr(p) <= r) return true; + function crs(_) { + if (!_.crs) return; + if (typeof _.crs === 'object') { + var strErr = requiredProperty(_.crs, 'type', 'string'), + propErr = requiredProperty(_.crs, 'properties', 'object'); + if (!strErr && !propErr) { + // http://geojson.org/geojson-spec.html#named-crs + if (_.crs.type === 'name') { + requiredProperty(_.crs.properties, 'name', 'string'); + } else if (_.crs.type === 'link') { + requiredProperty(_.crs.properties, 'href', 'string'); + } + } + } else { + errors.push({ + message: 'the value of the crs property must be an object, not a ' + (typeof _.crs), + line: _.__line__ + }); } } - return false; -} - -},{"../util/util":113,"./buffer":17,"./load_geometry":23,"point-geometry":162,"rbush":163,"vector-tile":168}],21:[function(require,module,exports){ -'use strict'; - -var Bucket = require('./bucket'); -var util = require('../util/util'); -var loadGeometry = require('./load_geometry'); - -module.exports = FillBucket; - -function FillBucket() { - Bucket.apply(this, arguments); -} - -FillBucket.prototype = util.inherit(Bucket, {}); -FillBucket.prototype.shaders = { - fill: { - vertexBuffer: true, - elementBuffer: true, - secondElementBuffer: true, - secondElementBufferComponents: 2, - - attributeArgs: ['x', 'y'], - - attributes: [{ - name: 'pos', - components: 2, - type: Bucket.AttributeType.SHORT, - value: ['x', 'y'] - }] + function bbox(_) { + if (!_.bbox) { return; } + if (Array.isArray(_.bbox)) { + if (!everyIs(_.bbox, 'number')) { + return errors.push({ + message: 'each element in a bbox property must be a number', + line: _.bbox.__line__ + }); + } + } else { + errors.push({ + message: 'bbox property must be an array of numbers, but is a ' + (typeof _.bbox), + line: _.__line__ + }); + } } -}; -FillBucket.prototype.addFeature = function(feature) { - var lines = loadGeometry(feature); - for (var i = 0; i < lines.length; i++) { - this.addFill(lines[i]); + // http://geojson.org/geojson-spec.html#point + function Point(point) { + crs(point); + bbox(point); + if (!requiredProperty(point, 'coordinates', 'array')) { + position(point.coordinates); + } } -}; -FillBucket.prototype.addFill = function(vertices) { - if (vertices.length < 3) { - //console.warn('a fill must have at least three vertices'); - return; + // http://geojson.org/geojson-spec.html#polygon + function Polygon(polygon) { + crs(polygon); + bbox(polygon); + if (!requiredProperty(polygon, 'coordinates', 'array')) { + positionArray(polygon.coordinates, 'LinearRing', 2); + } } - // Calculate the total number of vertices we're going to produce so that we - // can resize the buffer beforehand, or detect whether the current line - // won't fit into the buffer anymore. - // In order to be able to use the vertex buffer for drawing the antialiased - // outlines, we separate all polygon vertices with a degenerate (out-of- - // viewplane) vertex. - - var len = vertices.length; - - // Expand this geometry buffer to hold all the required vertices. - var group = this.makeRoomFor('fill', len + 1); + // http://geojson.org/geojson-spec.html#multipolygon + function MultiPolygon(multiPolygon) { + crs(multiPolygon); + bbox(multiPolygon); + if (!requiredProperty(multiPolygon, 'coordinates', 'array')) { + positionArray(multiPolygon.coordinates, 'LinearRing', 3); + } + } - // We're generating triangle fans, so we always start with the first coordinate in this polygon. - var firstIndex, prevIndex; - for (var i = 0; i < vertices.length; i++) { - var currentVertex = vertices[i]; + // http://geojson.org/geojson-spec.html#linestring + function LineString(lineString) { + crs(lineString); + bbox(lineString); + if (!requiredProperty(lineString, 'coordinates', 'array')) { + positionArray(lineString.coordinates, 'Line', 1); + } + } - var currentIndex = this.addFillVertex(currentVertex.x, currentVertex.y) - group.vertexStartIndex; - group.vertexLength++; - if (i === 0) firstIndex = currentIndex; + // http://geojson.org/geojson-spec.html#multilinestring + function MultiLineString(multiLineString) { + crs(multiLineString); + bbox(multiLineString); + if (!requiredProperty(multiLineString, 'coordinates', 'array')) { + positionArray(multiLineString.coordinates, 'Line', 2); + } + } - // Only add triangles that have distinct vertices. - if (i >= 2 && (currentVertex.x !== vertices[0].x || currentVertex.y !== vertices[0].y)) { - this.addFillElement(firstIndex, prevIndex, currentIndex); - group.elementLength++; + // http://geojson.org/geojson-spec.html#multipoint + function MultiPoint(multiPoint) { + crs(multiPoint); + bbox(multiPoint); + if (!requiredProperty(multiPoint, 'coordinates', 'array')) { + positionArray(multiPoint.coordinates, '', 1); } + } - if (i >= 1) { - this.addFillSecondElement(prevIndex, currentIndex); - group.secondElementLength++; + function GeometryCollection(geometryCollection) { + crs(geometryCollection); + bbox(geometryCollection); + if (!requiredProperty(geometryCollection, 'geometries', 'array')) { + geometryCollection.geometries.forEach(function(geometry) { + if (geometry) root(geometry); + }); } + } - prevIndex = currentIndex; + function Feature(feature) { + crs(feature); + bbox(feature); + // https://github.com/geojson/draft-geojson/blob/master/middle.mkd#feature-object + if (feature.id !== undefined && + typeof feature.id !== 'string' && + typeof feature.id !== 'number') { + errors.push({ + message: 'Feature "id" property must have a string or number value', + line: feature.__line__ + }); + } + if (feature.type !== 'Feature') { + errors.push({ + message: 'GeoJSON features must have a type=feature property', + line: feature.__line__ + }); + } + requiredProperty(feature, 'properties', 'object'); + if (!requiredProperty(feature, 'geometry', 'object')) { + // http://geojson.org/geojson-spec.html#feature-objects + // tolerate null geometry + if (feature.geometry) root(feature.geometry); + } } -}; -},{"../util/util":113,"./bucket":16,"./load_geometry":23}],22:[function(require,module,exports){ -'use strict'; + var types = { + Point: Point, + Feature: Feature, + MultiPoint: MultiPoint, + LineString: LineString, + MultiLineString: MultiLineString, + FeatureCollection: FeatureCollection, + GeometryCollection: GeometryCollection, + Polygon: Polygon, + MultiPolygon: MultiPolygon + }; -var Bucket = require('./bucket'); -var util = require('../util/util'); -var loadGeometry = require('./load_geometry'); + if (typeof gj !== 'object' || + gj === null || + gj === undefined) { + errors.push({ + message: 'The root of a GeoJSON object must be an object.', + line: 0 + }); + return errors; + } -// NOTE ON EXTRUDE SCALE: -// scale the extrusion vector so that the normal length is this value. -// contains the "texture" normals (-1..1). this is distinct from the extrude -// normals for line joins, because the x-value remains 0 for the texture -// normal array, while the extrude normal actually moves the vertex to create -// the acute/bevelled line join. -var EXTRUDE_SCALE = 63; + root(gj); -module.exports = LineBucket; + errors.forEach(function(err) { + if (err.hasOwnProperty('line') && err.line === undefined) { + delete err.line; + } + }); -function LineBucket() { - Bucket.apply(this, arguments); + return errors; } -LineBucket.prototype = util.inherit(Bucket, {}); +module.exports.hint = hint; -LineBucket.prototype.shaders = { - line: { - vertexBuffer: true, - elementBuffer: true, - - attributeArgs: ['point', 'extrude', 'tx', 'ty', 'dir', 'linesofar'], - - attributes: [{ - name: 'pos', - components: 2, - type: Bucket.AttributeType.SHORT, - value: [ - '(point.x << 1) | tx', - '(point.y << 1) | ty' - ] - }, { - name: 'data', - components: 4, - type: Bucket.AttributeType.BYTE, - value: [ - 'Math.round(' + EXTRUDE_SCALE + ' * extrude.x)', - 'Math.round(' + EXTRUDE_SCALE + ' * extrude.y)', - - // Encode the -1/0/1 direction value into .zw coordinates of a_data, which is normally covered - // by linesofar, so we need to merge them. - // The z component's first bit, as well as the sign bit is reserved for the direction, - // so we need to shift the linesofar. - '((dir < 0) ? -1 : 1) * ((dir ? 1 : 0) | ((linesofar << 1) & 0x7F))', - '(linesofar >> 6) & 0x7F' - ] - }] - } -}; - -LineBucket.prototype.addFeature = function(feature) { - var lines = loadGeometry(feature); - for (var i = 0; i < lines.length; i++) { - this.addLine( - lines[i], - this.layer.layout['line-join'], - this.layer.layout['line-cap'], - this.layer.layout['line-miter-limit'], - this.layer.layout['line-round-limit'] - ); - } -}; +},{}],29:[function(require,module,exports){ +/** + * @fileoverview gl-matrix - High performance matrix and vector operations + * @author Brandon Jones + * @author Colin MacKenzie IV + * @version 2.3.2 + */ -LineBucket.prototype.addLine = function(vertices, join, cap, miterLimit, roundLimit) { +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - var len = vertices.length; - // If the line has duplicate vertices at the end, adjust length to remove them. - while (len > 2 && vertices[len - 1].equals(vertices[len - 2])) { - len--; - } +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: - if (vertices.length < 2) { - //console.warn('a line must have at least two vertices'); - return; - } +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - if (join === 'bevel') miterLimit = 1.05; +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. */ +// END HEADER - var firstVertex = vertices[0], - lastVertex = vertices[len - 1], - closed = firstVertex.equals(lastVertex); +exports.glMatrix = require("./gl-matrix/common.js"); +exports.mat2 = require("./gl-matrix/mat2.js"); +exports.mat2d = require("./gl-matrix/mat2d.js"); +exports.mat3 = require("./gl-matrix/mat3.js"); +exports.mat4 = require("./gl-matrix/mat4.js"); +exports.quat = require("./gl-matrix/quat.js"); +exports.vec2 = require("./gl-matrix/vec2.js"); +exports.vec3 = require("./gl-matrix/vec3.js"); +exports.vec4 = require("./gl-matrix/vec4.js"); +},{"./gl-matrix/common.js":30,"./gl-matrix/mat2.js":31,"./gl-matrix/mat2d.js":32,"./gl-matrix/mat3.js":33,"./gl-matrix/mat4.js":34,"./gl-matrix/quat.js":35,"./gl-matrix/vec2.js":36,"./gl-matrix/vec3.js":37,"./gl-matrix/vec4.js":38}],30:[function(require,module,exports){ +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - // we could be more precise, but it would only save a negligible amount of space - this.makeRoomFor('line', len * 10); +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: - if (len === 2 && closed) { - // console.warn('a line may not have coincident points'); - return; - } +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - var beginCap = cap, - endCap = closed ? 'butt' : cap, - flip = 1, - distance = 0, - startOfLine = true, - currentVertex, prevVertex, nextVertex, prevNormal, nextNormal, offsetA, offsetB; +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. */ - // the last three vertices added - this.e1 = this.e2 = this.e3 = -1; +/** + * @class Common utilities + * @name glMatrix + */ +var glMatrix = {}; - if (closed) { - currentVertex = vertices[len - 2]; - nextNormal = firstVertex.sub(currentVertex)._unit()._perp(); - } +// Configuration Constants +glMatrix.EPSILON = 0.000001; +glMatrix.ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array; +glMatrix.RANDOM = Math.random; +glMatrix.ENABLE_SIMD = false; - for (var i = 0; i < len; i++) { +// Capability detection +glMatrix.SIMD_AVAILABLE = (glMatrix.ARRAY_TYPE === Float32Array) && ('SIMD' in this); +glMatrix.USE_SIMD = glMatrix.ENABLE_SIMD && glMatrix.SIMD_AVAILABLE; - nextVertex = closed && i === len - 1 ? - vertices[1] : // if the line is closed, we treat the last vertex like the first - vertices[i + 1]; // just the next vertex +/** + * Sets the type of array used when creating new vectors and matrices + * + * @param {Type} type Array type, such as Float32Array or Array + */ +glMatrix.setMatrixArrayType = function(type) { + glMatrix.ARRAY_TYPE = type; +} - // if two consecutive vertices exist, skip the current one - if (nextVertex && vertices[i].equals(nextVertex)) continue; +var degree = Math.PI / 180; - if (nextNormal) prevNormal = nextNormal; - if (currentVertex) prevVertex = currentVertex; +/** +* Convert Degree To Radian +* +* @param {Number} Angle in Degrees +*/ +glMatrix.toRadian = function(a){ + return a * degree; +} - currentVertex = vertices[i]; +/** + * Tests whether or not the arguments have approximately the same value, within an absolute + * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less + * than or equal to 1.0, and a relative tolerance is used for larger values) + * + * @param {Number} a The first number to test. + * @param {Number} b The second number to test. + * @returns {Boolean} True if the numbers are approximately equal, false otherwise. + */ +glMatrix.equals = function(a, b) { + return Math.abs(a - b) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a), Math.abs(b)); +} - // Calculate how far along the line the currentVertex is - if (prevVertex) distance += currentVertex.dist(prevVertex); +module.exports = glMatrix; - // Calculate the normal towards the next vertex in this line. In case - // there is no next vertex, pretend that the line is continuing straight, - // meaning that we are just using the previous normal. - nextNormal = nextVertex ? nextVertex.sub(currentVertex)._unit()._perp() : prevNormal; +},{}],31:[function(require,module,exports){ +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - // If we still don't have a previous normal, this is the beginning of a - // non-closed line, so we're doing a straight "join". - prevNormal = prevNormal || nextNormal; +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: - // Determine the normal of the join extrusion. It is the angle bisector - // of the segments between the previous line and the next line. - var joinNormal = prevNormal.add(nextNormal)._unit(); +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - /* joinNormal prevNormal - * ↖ ↑ - * .________. prevVertex - * | - * nextNormal ← | currentVertex - * | - * nextVertex ! - * - */ - - // Calculate the length of the miter (the ratio of the miter to the width). - // Find the cosine of the angle between the next and join normals - // using dot product. The inverse of that is the miter length. - var cosHalfAngle = joinNormal.x * nextNormal.x + joinNormal.y * nextNormal.y; - var miterLength = 1 / cosHalfAngle; +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. */ - // The join if a middle vertex, otherwise the cap. - var middleVertex = prevVertex && nextVertex; - var currentJoin = middleVertex ? join : nextVertex ? beginCap : endCap; +var glMatrix = require("./common.js"); - if (middleVertex && currentJoin === 'round') { - if (miterLength < roundLimit) { - currentJoin = 'miter'; - } else if (miterLength <= 2) { - currentJoin = 'fakeround'; - } - } +/** + * @class 2x2 Matrix + * @name mat2 + */ +var mat2 = {}; - if (currentJoin === 'miter' && miterLength > miterLimit) { - currentJoin = 'bevel'; - } +/** + * Creates a new identity mat2 + * + * @returns {mat2} a new 2x2 matrix + */ +mat2.create = function() { + var out = new glMatrix.ARRAY_TYPE(4); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +}; - if (currentJoin === 'bevel') { - // The maximum extrude length is 128 / 63 = 2 times the width of the line - // so if miterLength >= 2 we need to draw a different type of bevel where. - if (miterLength > 2) currentJoin = 'flipbevel'; +/** + * Creates a new mat2 initialized with values from an existing matrix + * + * @param {mat2} a matrix to clone + * @returns {mat2} a new 2x2 matrix + */ +mat2.clone = function(a) { + var out = new glMatrix.ARRAY_TYPE(4); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +}; - // If the miterLength is really small and the line bevel wouldn't be visible, - // just draw a miter join to save a triangle. - if (miterLength < miterLimit) currentJoin = 'miter'; - } +/** + * Copy the values from one mat2 to another + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +mat2.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +}; - if (currentJoin === 'miter') { +/** + * Set a mat2 to the identity matrix + * + * @param {mat2} out the receiving matrix + * @returns {mat2} out + */ +mat2.identity = function(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +}; - joinNormal._mult(miterLength); - this.addCurrentVertex(currentVertex, flip, distance, joinNormal, 0, 0, false); +/** + * Create a new mat2 with the given values + * + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m10 Component in column 1, row 0 position (index 2) + * @param {Number} m11 Component in column 1, row 1 position (index 3) + * @returns {mat2} out A new 2x2 matrix + */ +mat2.fromValues = function(m00, m01, m10, m11) { + var out = new glMatrix.ARRAY_TYPE(4); + out[0] = m00; + out[1] = m01; + out[2] = m10; + out[3] = m11; + return out; +}; - } else if (currentJoin === 'flipbevel') { - // miter is too big, flip the direction to make a beveled join +/** + * Set the components of a mat2 to the given values + * + * @param {mat2} out the receiving matrix + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m10 Component in column 1, row 0 position (index 2) + * @param {Number} m11 Component in column 1, row 1 position (index 3) + * @returns {mat2} out + */ +mat2.set = function(out, m00, m01, m10, m11) { + out[0] = m00; + out[1] = m01; + out[2] = m10; + out[3] = m11; + return out; +}; - if (miterLength > 100) { - // Almost parallel lines - joinNormal = nextNormal.clone(); - } else { - var direction = prevNormal.x * nextNormal.y - prevNormal.y * nextNormal.x > 0 ? -1 : 1; - var bevelLength = miterLength * prevNormal.add(nextNormal).mag() / prevNormal.sub(nextNormal).mag(); - joinNormal._perp()._mult(bevelLength * direction); - } - this.addCurrentVertex(currentVertex, flip, distance, joinNormal, 0, 0, false); - this.addCurrentVertex(currentVertex, -flip, distance, joinNormal, 0, 0, false); +/** + * Transpose the values of a mat2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +mat2.transpose = function(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (out === a) { + var a1 = a[1]; + out[1] = a[2]; + out[2] = a1; + } else { + out[0] = a[0]; + out[1] = a[2]; + out[2] = a[1]; + out[3] = a[3]; + } + + return out; +}; - } else if (currentJoin === 'bevel' || currentJoin === 'fakeround') { - var lineTurnsLeft = flip * (prevNormal.x * nextNormal.y - prevNormal.y * nextNormal.x) > 0; - var offset = -Math.sqrt(miterLength * miterLength - 1); - if (lineTurnsLeft) { - offsetB = 0; - offsetA = offset; - } else { - offsetA = 0; - offsetB = offset; - } +/** + * Inverts a mat2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +mat2.invert = function(out, a) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], - // Close previous segment with a bevel - if (!startOfLine) { - this.addCurrentVertex(currentVertex, flip, distance, prevNormal, offsetA, offsetB, false); - } - - if (currentJoin === 'fakeround') { - // The join angle is sharp enough that a round join would be visible. - // Bevel joins fill the gap between segments with a single pie slice triangle. - // Create a round join by adding multiple pie slices. The join isn't actually round, but - // it looks like it is at the sizes we render lines at. - - // Add more triangles for sharper angles. - // This math is just a good enough approximation. It isn't "correct". - var n = Math.floor((0.5 - (cosHalfAngle - 0.5)) * 8); - var approxFractionalJoinNormal; - - for (var m = 0; m < n; m++) { - approxFractionalJoinNormal = nextNormal.mult((m + 1) / (n + 1))._add(prevNormal)._unit(); - this.addPieSliceVertex(currentVertex, flip, distance, approxFractionalJoinNormal, lineTurnsLeft); - } - - this.addPieSliceVertex(currentVertex, flip, distance, joinNormal, lineTurnsLeft); - - for (var k = n - 1; k >= 0; k--) { - approxFractionalJoinNormal = prevNormal.mult((k + 1) / (n + 1))._add(nextNormal)._unit(); - this.addPieSliceVertex(currentVertex, flip, distance, approxFractionalJoinNormal, lineTurnsLeft); - } - } - - // Start next segment - if (nextVertex) { - this.addCurrentVertex(currentVertex, flip, distance, nextNormal, -offsetA, -offsetB, false); - } - - } else if (currentJoin === 'butt') { - if (!startOfLine) { - // Close previous segment with a butt - this.addCurrentVertex(currentVertex, flip, distance, prevNormal, 0, 0, false); - } - - // Start next segment with a butt - if (nextVertex) { - this.addCurrentVertex(currentVertex, flip, distance, nextNormal, 0, 0, false); - } - - } else if (currentJoin === 'square') { - - if (!startOfLine) { - // Close previous segment with a square cap - this.addCurrentVertex(currentVertex, flip, distance, prevNormal, 1, 1, false); - - // The segment is done. Unset vertices to disconnect segments. - this.e1 = this.e2 = -1; - flip = 1; - } - - // Start next segment - if (nextVertex) { - this.addCurrentVertex(currentVertex, flip, distance, nextNormal, -1, -1, false); - } + // Calculate the determinant + det = a0 * a3 - a2 * a1; - } else if (currentJoin === 'round') { + if (!det) { + return null; + } + det = 1.0 / det; + + out[0] = a3 * det; + out[1] = -a1 * det; + out[2] = -a2 * det; + out[3] = a0 * det; - if (!startOfLine) { - // Close previous segment with butt - this.addCurrentVertex(currentVertex, flip, distance, prevNormal, 0, 0, false); + return out; +}; - // Add round cap or linejoin at end of segment - this.addCurrentVertex(currentVertex, flip, distance, prevNormal, 1, 1, true); +/** + * Calculates the adjugate of a mat2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +mat2.adjoint = function(out, a) { + // Caching this value is nessecary if out == a + var a0 = a[0]; + out[0] = a[3]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = a0; - // The segment is done. Unset vertices to disconnect segments. - this.e1 = this.e2 = -1; - flip = 1; - } + return out; +}; +/** + * Calculates the determinant of a mat2 + * + * @param {mat2} a the source matrix + * @returns {Number} determinant of a + */ +mat2.determinant = function (a) { + return a[0] * a[3] - a[2] * a[1]; +}; - // Start next segment with a butt - if (nextVertex) { - // Add round cap before first segment - this.addCurrentVertex(currentVertex, flip, distance, nextNormal, -1, -1, true); +/** + * Multiplies two mat2's + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the first operand + * @param {mat2} b the second operand + * @returns {mat2} out + */ +mat2.multiply = function (out, a, b) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; + var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + out[0] = a0 * b0 + a2 * b1; + out[1] = a1 * b0 + a3 * b1; + out[2] = a0 * b2 + a2 * b3; + out[3] = a1 * b2 + a3 * b3; + return out; +}; - this.addCurrentVertex(currentVertex, flip, distance, nextNormal, 0, 0, false); - } - } +/** + * Alias for {@link mat2.multiply} + * @function + */ +mat2.mul = mat2.multiply; - startOfLine = false; - } +/** + * Rotates a mat2 by the given angle + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2} out + */ +mat2.rotate = function (out, a, rad) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], + s = Math.sin(rad), + c = Math.cos(rad); + out[0] = a0 * c + a2 * s; + out[1] = a1 * c + a3 * s; + out[2] = a0 * -s + a2 * c; + out[3] = a1 * -s + a3 * c; + return out; +}; +/** + * Scales the mat2 by the dimensions in the given vec2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the matrix to rotate + * @param {vec2} v the vec2 to scale the matrix by + * @returns {mat2} out + **/ +mat2.scale = function(out, a, v) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], + v0 = v[0], v1 = v[1]; + out[0] = a0 * v0; + out[1] = a1 * v0; + out[2] = a2 * v1; + out[3] = a3 * v1; + return out; }; /** - * Add two vertices to the buffers. + * Creates a matrix from a given angle + * This is equivalent to (but much faster than): * - * @param {Object} currentVertex the line vertex to add buffer vertices for - * @param {number} flip -1 if the vertices should be flipped, 1 otherwise - * @param {number} distance the distance from the beginning of the line to the vertex - * @param {number} endLeft extrude to shift the left vertex along the line - * @param {number} endRight extrude to shift the left vertex along the line - * @param {boolean} round whether this is a round cap - * @private + * mat2.identity(dest); + * mat2.rotate(dest, dest, rad); + * + * @param {mat2} out mat2 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2} out */ -LineBucket.prototype.addCurrentVertex = function(currentVertex, flip, distance, normal, endLeft, endRight, round) { - var tx = round ? 1 : 0; - var extrude; - var group = this.elementGroups.line.current; - group.vertexLength += 2; +mat2.fromRotation = function(out, rad) { + var s = Math.sin(rad), + c = Math.cos(rad); + out[0] = c; + out[1] = s; + out[2] = -s; + out[3] = c; + return out; +} - extrude = normal.mult(flip); - if (endLeft) extrude._sub(normal.perp()._mult(endLeft)); - this.e3 = this.addLineVertex(currentVertex, extrude, tx, 0, endLeft, distance) - group.vertexStartIndex; - if (this.e1 >= 0 && this.e2 >= 0) { - this.addLineElement(this.e1, this.e2, this.e3); - group.elementLength++; - } - this.e1 = this.e2; - this.e2 = this.e3; +/** + * Creates a matrix from a vector scaling + * This is equivalent to (but much faster than): + * + * mat2.identity(dest); + * mat2.scale(dest, dest, vec); + * + * @param {mat2} out mat2 receiving operation result + * @param {vec2} v Scaling vector + * @returns {mat2} out + */ +mat2.fromScaling = function(out, v) { + out[0] = v[0]; + out[1] = 0; + out[2] = 0; + out[3] = v[1]; + return out; +} - extrude = normal.mult(-flip); - if (endRight) extrude._sub(normal.perp()._mult(endRight)); - this.e3 = this.addLineVertex(currentVertex, extrude, tx, 1, -endRight, distance) - group.vertexStartIndex; - if (this.e1 >= 0 && this.e2 >= 0) { - this.addLineElement(this.e1, this.e2, this.e3); - group.elementLength++; - } - this.e1 = this.e2; - this.e2 = this.e3; +/** + * Returns a string representation of a mat2 + * + * @param {mat2} mat matrix to represent as a string + * @returns {String} string representation of the matrix + */ +mat2.str = function (a) { + return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; }; /** - * Add a single new vertex and a triangle using two previous vertices. - * This adds a pie slice triangle near a join to simulate round joins + * Returns Frobenius norm of a mat2 * - * @param {Object} currentVertex the line vertex to add buffer vertices for - * @param {number} flip -1 if the vertices should be flipped, 1 otherwise - * @param {number} distance the distance from the beggining of the line to the vertex - * @param {Object} extrude the offset of the new vertex from the currentVertex - * @param {boolean} whether the line is turning left or right at this angle - * @private + * @param {mat2} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm */ -LineBucket.prototype.addPieSliceVertex = function(currentVertex, flip, distance, extrude, lineTurnsLeft) { - var ty = lineTurnsLeft ? 1 : 0; - extrude = extrude.mult(flip * (lineTurnsLeft ? -1 : 1)); - var group = this.elementGroups.line.current; +mat2.frob = function (a) { + return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2))) +}; - this.e3 = this.addLineVertex(currentVertex, extrude, 0, ty, 0, distance) - group.vertexStartIndex; - group.vertexLength++; +/** + * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix + * @param {mat2} L the lower triangular matrix + * @param {mat2} D the diagonal matrix + * @param {mat2} U the upper triangular matrix + * @param {mat2} a the input matrix to factorize + */ - if (this.e1 >= 0 && this.e2 >= 0) { - this.addLineElement(this.e1, this.e2, this.e3); - group.elementLength++; - } +mat2.LDU = function (L, D, U, a) { + L[2] = a[2]/a[0]; + U[0] = a[0]; + U[1] = a[1]; + U[3] = a[3] - L[2] * U[1]; + return [L, D, U]; +}; - if (lineTurnsLeft) { - this.e2 = this.e3; - } else { - this.e1 = this.e3; - } +/** + * Adds two mat2's + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the first operand + * @param {mat2} b the second operand + * @returns {mat2} out + */ +mat2.add = function(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + return out; }; -},{"../util/util":113,"./bucket":16,"./load_geometry":23}],23:[function(require,module,exports){ -'use strict'; +/** + * Subtracts matrix b from matrix a + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the first operand + * @param {mat2} b the second operand + * @returns {mat2} out + */ +mat2.subtract = function(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + return out; +}; -var EXTENT = require('./buffer').EXTENT; +/** + * Alias for {@link mat2.subtract} + * @function + */ +mat2.sub = mat2.subtract; /** - * Loads a geometry from a VectorTileFeature and scales it to the common extent - * used internally. - * @private + * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) + * + * @param {mat2} a The first matrix. + * @param {mat2} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. */ -module.exports = function loadGeometry(feature) { - var scale = EXTENT / feature.extent; - var geometry = feature.loadGeometry(); - for (var r = 0; r < geometry.length; r++) { - var ring = geometry[r]; - for (var p = 0; p < ring.length; p++) { - var point = ring[p]; - // round here because mapbox-gl-native uses integers to represent - // points and we need to do the same to avoid renering differences. - point.x = Math.round(point.x * scale); - point.y = Math.round(point.y * scale); - } - } - return geometry; +mat2.exactEquals = function (a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]; }; -},{"./buffer":17}],24:[function(require,module,exports){ -'use strict'; - -var Point = require('point-geometry'); - -var Bucket = require('./bucket'); -var ElementGroups = require('./element_groups'); -var Anchor = require('../symbol/anchor'); -var getAnchors = require('../symbol/get_anchors'); -var resolveTokens = require('../util/token'); -var Quads = require('../symbol/quads'); -var Shaping = require('../symbol/shaping'); -var resolveText = require('../symbol/resolve_text'); -var mergeLines = require('../symbol/mergelines'); -var shapeText = Shaping.shapeText; -var shapeIcon = Shaping.shapeIcon; -var getGlyphQuads = Quads.getGlyphQuads; -var getIconQuads = Quads.getIconQuads; -var clipLine = require('../symbol/clip_line'); -var util = require('../util/util'); -var loadGeometry = require('./load_geometry'); -var EXTENT = require('./buffer').EXTENT; - -var CollisionFeature = require('../symbol/collision_feature'); - -module.exports = SymbolBucket; - -function SymbolBucket(options) { - Bucket.apply(this, arguments); - this.collisionDebug = options.collisionDebug; - this.overscaling = options.overscaling; - - // To reduce the number of labels that jump around when zooming we need - // to use a text-size value that is the same for all zoom levels. - // This calculates text-size at a high zoom level so that all tiles can - // use the same value when calculating anchor positions. - var zoomHistory = { lastIntegerZoom: Infinity, lastIntegerZoomTime: 0, lastZoom: 0 }; +/** + * Returns whether or not the matrices have approximately the same elements in the same position. + * + * @param {mat2} a The first matrix. + * @param {mat2} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ +mat2.equals = function (a, b) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; + var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && + Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) && + Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) && + Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3))); +}; - this.adjustedTextMaxSize = this.layer.getLayoutValue('text-size', 18, zoomHistory); - this.adjustedTextSize = this.layer.getLayoutValue('text-size', this.zoom + 1, zoomHistory); +/** + * Multiply each element of the matrix by a scalar. + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the matrix to scale + * @param {Number} b amount to scale the matrix's elements by + * @returns {mat2} out + */ +mat2.multiplyScalar = function(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + return out; +}; - this.adjustedIconMaxSize = this.layer.getLayoutValue('icon-size', 18, zoomHistory); - this.adjustedIconSize = this.layer.getLayoutValue('icon-size', this.zoom + 1, zoomHistory); -} +/** + * Adds two mat2's after multiplying each element of the second operand by a scalar value. + * + * @param {mat2} out the receiving vector + * @param {mat2} a the first operand + * @param {mat2} b the second operand + * @param {Number} scale the amount to scale b's elements by before adding + * @returns {mat2} out + */ +mat2.multiplyScalarAndAdd = function(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + out[2] = a[2] + (b[2] * scale); + out[3] = a[3] + (b[3] * scale); + return out; +}; -SymbolBucket.prototype = util.inherit(Bucket, {}); +module.exports = mat2; -var shaderAttributeArgs = ['x', 'y', 'ox', 'oy', 'tx', 'ty', 'minzoom', 'maxzoom', 'labelminzoom']; - -var shaderAttributes = [{ - name: 'pos', - components: 2, - type: Bucket.AttributeType.SHORT, - value: ['x', 'y'] -}, { - name: 'offset', - components: 2, - type: Bucket.AttributeType.SHORT, - value: [ - 'Math.round(ox * 64)', // use 1/64 pixels for placement - 'Math.round(oy * 64)' - ] -}, { - name: 'data1', - components: 4, - type: Bucket.AttributeType.UNSIGNED_BYTE, - value: [ - 'tx / 4', // tex - 'ty / 4', // tex - '(labelminzoom || 0) * 10', // labelminzoom - '0' - ] -}, { - name: 'data2', - components: 2, - type: Bucket.AttributeType.UNSIGNED_BYTE, - value: [ - '(minzoom || 0) * 10', // minzoom - 'Math.min(maxzoom || 25, 25) * 10' // minzoom - ] -}]; +},{"./common.js":30}],32:[function(require,module,exports){ +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. -SymbolBucket.prototype.shaders = { +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: - glyph: { - vertexBuffer: true, - elementBuffer: true, - attributeArgs: shaderAttributeArgs, - attributes: shaderAttributes - }, +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - icon: { - vertexBuffer: true, - elementBuffer: true, - attributeArgs: shaderAttributeArgs, - attributes: shaderAttributes - }, +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. */ - collisionBox: { - vertexBuffer: true, - - attributeArgs: ['point', 'extrude', 'maxZoom', 'placementZoom'], - - attributes: [{ - name: 'pos', - components: 2, - type: Bucket.AttributeType.SHORT, - value: [ 'point.x', 'point.y' ] - }, { - name: 'extrude', - components: 2, - type: Bucket.AttributeType.SHORT, - value: [ - 'Math.round(extrude.x)', - 'Math.round(extrude.y)' - ] - }, { - name: 'data', - components: 2, - type: Bucket.AttributeType.UNSIGNED_BYTE, - value: [ - 'maxZoom * 10', - 'placementZoom * 10' - ] - }] - } -}; - -SymbolBucket.prototype.addFeatures = function(collisionTile, stacks, icons) { - var tileSize = 512 * this.overscaling; - this.tilePixelRatio = EXTENT / tileSize; - this.compareText = {}; - this.symbolInstances = []; - this.iconsNeedLinear = false; +var glMatrix = require("./common.js"); - var layout = this.layer.layout; - var features = this.features; - var textFeatures = this.textFeatures; +/** + * @class 2x3 Matrix + * @name mat2d + * + * @description + * A mat2d contains six elements defined as: + *
+ * [a, c, tx,
+ *  b, d, ty]
+ * 
+ * This is a short form for the 3x3 matrix: + *
+ * [a, c, tx,
+ *  b, d, ty,
+ *  0, 0, 1]
+ * 
+ * The last row is ignored so the array is shorter and operations are faster. + */ +var mat2d = {}; - var horizontalAlign = 0.5, - verticalAlign = 0.5; +/** + * Creates a new identity mat2d + * + * @returns {mat2d} a new 2x3 matrix + */ +mat2d.create = function() { + var out = new glMatrix.ARRAY_TYPE(6); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = 0; + out[5] = 0; + return out; +}; - switch (layout['text-anchor']) { - case 'right': - case 'top-right': - case 'bottom-right': - horizontalAlign = 1; - break; - case 'left': - case 'top-left': - case 'bottom-left': - horizontalAlign = 0; - break; - } +/** + * Creates a new mat2d initialized with values from an existing matrix + * + * @param {mat2d} a matrix to clone + * @returns {mat2d} a new 2x3 matrix + */ +mat2d.clone = function(a) { + var out = new glMatrix.ARRAY_TYPE(6); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + return out; +}; - switch (layout['text-anchor']) { - case 'bottom': - case 'bottom-right': - case 'bottom-left': - verticalAlign = 1; - break; - case 'top': - case 'top-right': - case 'top-left': - verticalAlign = 0; - break; - } +/** + * Copy the values from one mat2d to another + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the source matrix + * @returns {mat2d} out + */ +mat2d.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + return out; +}; - var justify = layout['text-justify'] === 'right' ? 1 : - layout['text-justify'] === 'left' ? 0 : - 0.5; +/** + * Set a mat2d to the identity matrix + * + * @param {mat2d} out the receiving matrix + * @returns {mat2d} out + */ +mat2d.identity = function(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = 0; + out[5] = 0; + return out; +}; - var oneEm = 24; - var lineHeight = layout['text-line-height'] * oneEm; - var maxWidth = layout['symbol-placement'] !== 'line' ? layout['text-max-width'] * oneEm : 0; - var spacing = layout['text-letter-spacing'] * oneEm; - var textOffset = [layout['text-offset'][0] * oneEm, layout['text-offset'][1] * oneEm]; - var fontstack = layout['text-font'].join(','); +/** + * Create a new mat2d with the given values + * + * @param {Number} a Component A (index 0) + * @param {Number} b Component B (index 1) + * @param {Number} c Component C (index 2) + * @param {Number} d Component D (index 3) + * @param {Number} tx Component TX (index 4) + * @param {Number} ty Component TY (index 5) + * @returns {mat2d} A new mat2d + */ +mat2d.fromValues = function(a, b, c, d, tx, ty) { + var out = new glMatrix.ARRAY_TYPE(6); + out[0] = a; + out[1] = b; + out[2] = c; + out[3] = d; + out[4] = tx; + out[5] = ty; + return out; +}; - var geometries = []; - for (var g = 0; g < features.length; g++) { - geometries.push(loadGeometry(features[g])); - } +/** + * Set the components of a mat2d to the given values + * + * @param {mat2d} out the receiving matrix + * @param {Number} a Component A (index 0) + * @param {Number} b Component B (index 1) + * @param {Number} c Component C (index 2) + * @param {Number} d Component D (index 3) + * @param {Number} tx Component TX (index 4) + * @param {Number} ty Component TY (index 5) + * @returns {mat2d} out + */ +mat2d.set = function(out, a, b, c, d, tx, ty) { + out[0] = a; + out[1] = b; + out[2] = c; + out[3] = d; + out[4] = tx; + out[5] = ty; + return out; +}; - if (layout['symbol-placement'] === 'line') { - // Merge adjacent lines with the same text to improve labelling. - // It's better to place labels on one long line than on many short segments. - var merged = mergeLines(features, textFeatures, geometries); +/** + * Inverts a mat2d + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the source matrix + * @returns {mat2d} out + */ +mat2d.invert = function(out, a) { + var aa = a[0], ab = a[1], ac = a[2], ad = a[3], + atx = a[4], aty = a[5]; - geometries = merged.geometries; - features = merged.features; - textFeatures = merged.textFeatures; + var det = aa * ad - ab * ac; + if(!det){ + return null; } + det = 1.0 / det; - var shapedText, shapedIcon; + out[0] = ad * det; + out[1] = -ab * det; + out[2] = -ac * det; + out[3] = aa * det; + out[4] = (ac * aty - ad * atx) * det; + out[5] = (ab * atx - aa * aty) * det; + return out; +}; - for (var k = 0; k < features.length; k++) { - if (!geometries[k]) continue; +/** + * Calculates the determinant of a mat2d + * + * @param {mat2d} a the source matrix + * @returns {Number} determinant of a + */ +mat2d.determinant = function (a) { + return a[0] * a[3] - a[1] * a[2]; +}; - if (textFeatures[k]) { - shapedText = shapeText(textFeatures[k], stacks[fontstack], maxWidth, - lineHeight, horizontalAlign, verticalAlign, justify, spacing, textOffset); - } else { - shapedText = null; - } - - if (layout['icon-image']) { - var iconName = resolveTokens(features[k].properties, layout['icon-image']); - var image = icons[iconName]; - shapedIcon = shapeIcon(image, layout); +/** + * Multiplies two mat2d's + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the first operand + * @param {mat2d} b the second operand + * @returns {mat2d} out + */ +mat2d.multiply = function (out, a, b) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], + b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5]; + out[0] = a0 * b0 + a2 * b1; + out[1] = a1 * b0 + a3 * b1; + out[2] = a0 * b2 + a2 * b3; + out[3] = a1 * b2 + a3 * b3; + out[4] = a0 * b4 + a2 * b5 + a4; + out[5] = a1 * b4 + a3 * b5 + a5; + return out; +}; - if (image) { - if (this.sdfIcons === undefined) { - this.sdfIcons = image.sdf; - } else if (this.sdfIcons !== image.sdf) { - console.warn('Style sheet warning: Cannot mix SDF and non-SDF icons in one buffer'); - } - if (image.pixelRatio !== 1) { - this.iconsNeedLinear = true; - } - } - } else { - shapedIcon = null; - } +/** + * Alias for {@link mat2d.multiply} + * @function + */ +mat2d.mul = mat2d.multiply; - if (shapedText || shapedIcon) { - this.addFeature(geometries[k], shapedText, shapedIcon); - } - } +/** + * Rotates a mat2d by the given angle + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2d} out + */ +mat2d.rotate = function (out, a, rad) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], + s = Math.sin(rad), + c = Math.cos(rad); + out[0] = a0 * c + a2 * s; + out[1] = a1 * c + a3 * s; + out[2] = a0 * -s + a2 * c; + out[3] = a1 * -s + a3 * c; + out[4] = a4; + out[5] = a5; + return out; +}; - this.placeFeatures(collisionTile, this.buffers, this.collisionDebug); +/** + * Scales the mat2d by the dimensions in the given vec2 + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to translate + * @param {vec2} v the vec2 to scale the matrix by + * @returns {mat2d} out + **/ +mat2d.scale = function(out, a, v) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], + v0 = v[0], v1 = v[1]; + out[0] = a0 * v0; + out[1] = a1 * v0; + out[2] = a2 * v1; + out[3] = a3 * v1; + out[4] = a4; + out[5] = a5; + return out; }; -SymbolBucket.prototype.addFeature = function(lines, shapedText, shapedIcon) { - var layout = this.layer.layout; +/** + * Translates the mat2d by the dimensions in the given vec2 + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to translate + * @param {vec2} v the vec2 to translate the matrix by + * @returns {mat2d} out + **/ +mat2d.translate = function(out, a, v) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], + v0 = v[0], v1 = v[1]; + out[0] = a0; + out[1] = a1; + out[2] = a2; + out[3] = a3; + out[4] = a0 * v0 + a2 * v1 + a4; + out[5] = a1 * v0 + a3 * v1 + a5; + return out; +}; - var glyphSize = 24; +/** + * Creates a matrix from a given angle + * This is equivalent to (but much faster than): + * + * mat2d.identity(dest); + * mat2d.rotate(dest, dest, rad); + * + * @param {mat2d} out mat2d receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2d} out + */ +mat2d.fromRotation = function(out, rad) { + var s = Math.sin(rad), c = Math.cos(rad); + out[0] = c; + out[1] = s; + out[2] = -s; + out[3] = c; + out[4] = 0; + out[5] = 0; + return out; +} - var fontScale = this.adjustedTextSize / glyphSize, - textMaxSize = this.adjustedTextMaxSize !== undefined ? this.adjustedTextMaxSize : this.adjustedTextSize, - textBoxScale = this.tilePixelRatio * fontScale, - textMaxBoxScale = this.tilePixelRatio * textMaxSize / glyphSize, - iconBoxScale = this.tilePixelRatio * this.adjustedIconSize, - symbolMinDistance = this.tilePixelRatio * layout['symbol-spacing'], - avoidEdges = layout['symbol-avoid-edges'], - textPadding = layout['text-padding'] * this.tilePixelRatio, - iconPadding = layout['icon-padding'] * this.tilePixelRatio, - textMaxAngle = layout['text-max-angle'] / 180 * Math.PI, - textAlongLine = layout['text-rotation-alignment'] === 'map' && layout['symbol-placement'] === 'line', - iconAlongLine = layout['icon-rotation-alignment'] === 'map' && layout['symbol-placement'] === 'line', - mayOverlap = layout['text-allow-overlap'] || layout['icon-allow-overlap'] || - layout['text-ignore-placement'] || layout['icon-ignore-placement'], - isLine = layout['symbol-placement'] === 'line', - textRepeatDistance = symbolMinDistance / 2; +/** + * Creates a matrix from a vector scaling + * This is equivalent to (but much faster than): + * + * mat2d.identity(dest); + * mat2d.scale(dest, dest, vec); + * + * @param {mat2d} out mat2d receiving operation result + * @param {vec2} v Scaling vector + * @returns {mat2d} out + */ +mat2d.fromScaling = function(out, v) { + out[0] = v[0]; + out[1] = 0; + out[2] = 0; + out[3] = v[1]; + out[4] = 0; + out[5] = 0; + return out; +} - if (isLine) { - lines = clipLine(lines, 0, 0, EXTENT, EXTENT); - } +/** + * Creates a matrix from a vector translation + * This is equivalent to (but much faster than): + * + * mat2d.identity(dest); + * mat2d.translate(dest, dest, vec); + * + * @param {mat2d} out mat2d receiving operation result + * @param {vec2} v Translation vector + * @returns {mat2d} out + */ +mat2d.fromTranslation = function(out, v) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = v[0]; + out[5] = v[1]; + return out; +} - for (var i = 0; i < lines.length; i++) { - var line = lines[i]; +/** + * Returns a string representation of a mat2d + * + * @param {mat2d} a matrix to represent as a string + * @returns {String} string representation of the matrix + */ +mat2d.str = function (a) { + return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + + a[3] + ', ' + a[4] + ', ' + a[5] + ')'; +}; - // Calculate the anchor points around which you want to place labels - var anchors; - if (isLine) { - anchors = getAnchors( - line, - symbolMinDistance, - textMaxAngle, - shapedText, - shapedIcon, - glyphSize, - textMaxBoxScale, - this.overscaling, - EXTENT - ); - } else { - anchors = [ new Anchor(line[0].x, line[0].y, 0) ]; - } +/** + * Returns Frobenius norm of a mat2d + * + * @param {mat2d} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ +mat2d.frob = function (a) { + return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1)) +}; - // For each potential label, create the placement features used to check for collisions, and the quads use for rendering. - for (var j = 0, len = anchors.length; j < len; j++) { - var anchor = anchors[j]; +/** + * Adds two mat2d's + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the first operand + * @param {mat2d} b the second operand + * @returns {mat2d} out + */ +mat2d.add = function(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + return out; +}; - if (shapedText && isLine) { - if (this.anchorIsTooClose(shapedText.text, textRepeatDistance, anchor)) { - continue; - } - } +/** + * Subtracts matrix b from matrix a + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the first operand + * @param {mat2d} b the second operand + * @returns {mat2d} out + */ +mat2d.subtract = function(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + out[4] = a[4] - b[4]; + out[5] = a[5] - b[5]; + return out; +}; - var inside = !(anchor.x < 0 || anchor.x > EXTENT || anchor.y < 0 || anchor.y > EXTENT); +/** + * Alias for {@link mat2d.subtract} + * @function + */ +mat2d.sub = mat2d.subtract; - if (avoidEdges && !inside) continue; - - // Normally symbol layers are drawn across tile boundaries. Only symbols - // with their anchors within the tile boundaries are added to the buffers - // to prevent symbols from being drawn twice. - // - // Symbols in layers with overlap are sorted in the y direction so that - // symbols lower on the canvas are drawn on top of symbols near the top. - // To preserve this order across tile boundaries these symbols can't - // be drawn across tile boundaries. Instead they need to be included in - // the buffers for both tiles and clipped to tile boundaries at draw time. - var addToBuffers = inside || mayOverlap; +/** + * Multiply each element of the matrix by a scalar. + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to scale + * @param {Number} b amount to scale the matrix's elements by + * @returns {mat2d} out + */ +mat2d.multiplyScalar = function(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + out[4] = a[4] * b; + out[5] = a[5] * b; + return out; +}; - this.symbolInstances.push(new SymbolInstance(anchor, line, shapedText, shapedIcon, layout, addToBuffers, this.symbolInstances.length, - textBoxScale, textPadding, textAlongLine, - iconBoxScale, iconPadding, iconAlongLine)); - } - } +/** + * Adds two mat2d's after multiplying each element of the second operand by a scalar value. + * + * @param {mat2d} out the receiving vector + * @param {mat2d} a the first operand + * @param {mat2d} b the second operand + * @param {Number} scale the amount to scale b's elements by before adding + * @returns {mat2d} out + */ +mat2d.multiplyScalarAndAdd = function(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + out[2] = a[2] + (b[2] * scale); + out[3] = a[3] + (b[3] * scale); + out[4] = a[4] + (b[4] * scale); + out[5] = a[5] + (b[5] * scale); + return out; }; -SymbolBucket.prototype.anchorIsTooClose = function(text, repeatDistance, anchor) { - var compareText = this.compareText; - if (!(text in compareText)) { - compareText[text] = []; - } else { - var otherAnchors = compareText[text]; - for (var k = otherAnchors.length - 1; k >= 0; k--) { - if (anchor.dist(otherAnchors[k]) < repeatDistance) { - // If it's within repeatDistance of one anchor, stop looking - return true; - } - } - } - // If anchor is not within repeatDistance of any other anchor, add to array - compareText[text].push(anchor); - return false; -}; - -SymbolBucket.prototype.placeFeatures = function(collisionTile, buffers, collisionDebug) { - // Calculate which labels can be shown and when they can be shown and - // create the bufers used for rendering. - - this.resetBuffers(buffers); - - var elementGroups = this.elementGroups = { - glyph: new ElementGroups(buffers.glyphVertex, buffers.glyphElement), - icon: new ElementGroups(buffers.iconVertex, buffers.iconElement), - sdfIcons: this.sdfIcons, - iconsNeedLinear: this.iconsNeedLinear - }; - - var layout = this.layer.layout; - var maxScale = collisionTile.maxScale; - - elementGroups.glyph.adjustedSize = this.adjustedTextSize; - elementGroups.icon.adjustedSize = this.adjustedIconSize; - - // Transfer the name of the fonstack back to the main thread along with the buffers. - // The draw function needs to know which fonstack's glyph atlas to bind when rendering. - elementGroups.glyph.fontstack = layout['text-font'].join(','); - - var textAlongLine = layout['text-rotation-alignment'] === 'map' && layout['symbol-placement'] === 'line'; - var iconAlongLine = layout['icon-rotation-alignment'] === 'map' && layout['symbol-placement'] === 'line'; - - var mayOverlap = layout['text-allow-overlap'] || layout['icon-allow-overlap'] || - layout['text-ignore-placement'] || layout['icon-ignore-placement']; - - // Sort symbols by their y position on the canvas so that they lower symbols - // are drawn on top of higher symbols. - // Don't sort symbols that won't overlap because it isn't necessary and - // because it causes more labels to pop in and out when rotating. - if (mayOverlap) { - var angle = collisionTile.angle; - var sin = Math.sin(angle), - cos = Math.cos(angle); - - this.symbolInstances.sort(function(a, b) { - var aRotated = (sin * a.x + cos * a.y) | 0; - var bRotated = (sin * b.x + cos * b.y) | 0; - return (aRotated - bRotated) || (b.index - a.index); - }); - } - - for (var p = 0; p < this.symbolInstances.length; p++) { - var symbolInstance = this.symbolInstances[p]; - var hasText = symbolInstance.hasText; - var hasIcon = symbolInstance.hasIcon; - - var iconWithoutText = layout['text-optional'] || !hasText, - textWithoutIcon = layout['icon-optional'] || !hasIcon; - - - // Calculate the scales at which the text and icon can be placed without collision. - - var glyphScale = hasText ? - collisionTile.placeCollisionFeature(symbolInstance.textCollisionFeature, - layout['text-allow-overlap'], layout['symbol-avoid-edges']) : - collisionTile.minScale; - - var iconScale = hasIcon ? - collisionTile.placeCollisionFeature(symbolInstance.iconCollisionFeature, - layout['icon-allow-overlap'], layout['symbol-avoid-edges']) : - collisionTile.minScale; - - - // Combine the scales for icons and text. - - if (!iconWithoutText && !textWithoutIcon) { - iconScale = glyphScale = Math.max(iconScale, glyphScale); - } else if (!textWithoutIcon && glyphScale) { - glyphScale = Math.max(iconScale, glyphScale); - } else if (!iconWithoutText && iconScale) { - iconScale = Math.max(iconScale, glyphScale); - } - - - // Insert final placement into collision tree and add glyphs/icons to buffers - - if (hasText) { - if (!layout['text-ignore-placement']) { - collisionTile.insertCollisionFeature(symbolInstance.textCollisionFeature, glyphScale); - } - if (glyphScale <= maxScale) { - this.addSymbols('glyph', symbolInstance.glyphQuads, glyphScale, layout['text-keep-upright'], textAlongLine, collisionTile.angle); - } - } - - if (hasIcon) { - if (!layout['icon-ignore-placement']) { - collisionTile.insertCollisionFeature(symbolInstance.iconCollisionFeature, iconScale); - } - if (iconScale <= maxScale) { - this.addSymbols('icon', symbolInstance.iconQuads, iconScale, layout['icon-keep-upright'], iconAlongLine, collisionTile.angle); - } - } - - } - - if (collisionDebug) this.addToDebugBuffers(collisionTile); -}; - -SymbolBucket.prototype.addSymbols = function(shaderName, quads, scale, keepUpright, alongLine, placementAngle) { - - var group = this.makeRoomFor(shaderName, 4 * quads.length); - - // TODO manual curry - var addElement = this[this.getAddMethodName(shaderName, 'element')].bind(this); - var addVertex = this[this.getAddMethodName(shaderName, 'vertex')].bind(this); - - var zoom = this.zoom; - var placementZoom = Math.max(Math.log(scale) / Math.LN2 + zoom, 0); - - for (var k = 0; k < quads.length; k++) { - - var symbol = quads[k], - angle = symbol.angle; - - // drop upside down versions of glyphs - var a = (angle + placementAngle + Math.PI) % (Math.PI * 2); - if (keepUpright && alongLine && (a <= Math.PI / 2 || a > Math.PI * 3 / 2)) continue; - - var tl = symbol.tl, - tr = symbol.tr, - bl = symbol.bl, - br = symbol.br, - tex = symbol.tex, - anchorPoint = symbol.anchorPoint, - - minZoom = Math.max(zoom + Math.log(symbol.minScale) / Math.LN2, placementZoom), - maxZoom = Math.min(zoom + Math.log(symbol.maxScale) / Math.LN2, 25); - - if (maxZoom <= minZoom) continue; - - // Lower min zoom so that while fading out the label it can be shown outside of collision-free zoom levels - if (minZoom === placementZoom) minZoom = 0; - - var index = addVertex(anchorPoint.x, anchorPoint.y, tl.x, tl.y, tex.x, tex.y, minZoom, maxZoom, placementZoom) - group.vertexStartIndex; - addVertex(anchorPoint.x, anchorPoint.y, tr.x, tr.y, tex.x + tex.w, tex.y, minZoom, maxZoom, placementZoom); - addVertex(anchorPoint.x, anchorPoint.y, bl.x, bl.y, tex.x, tex.y + tex.h, minZoom, maxZoom, placementZoom); - addVertex(anchorPoint.x, anchorPoint.y, br.x, br.y, tex.x + tex.w, tex.y + tex.h, minZoom, maxZoom, placementZoom); - group.vertexLength += 4; - - addElement(index, index + 1, index + 2); - addElement(index + 1, index + 2, index + 3); - group.elementLength += 2; - } - -}; - -SymbolBucket.prototype.updateIcons = function(icons) { - var iconValue = this.layer.layout['icon-image']; - if (!iconValue) return; - - for (var i = 0; i < this.features.length; i++) { - var iconName = resolveTokens(this.features[i].properties, iconValue); - if (iconName) - icons[iconName] = true; - } -}; - -SymbolBucket.prototype.updateFont = function(stacks) { - var fontName = this.layer.layout['text-font'], - stack = stacks[fontName] = stacks[fontName] || {}; - - this.textFeatures = resolveText(this.features, this.layer.layout, stack); -}; - -SymbolBucket.prototype.addToDebugBuffers = function(collisionTile) { - this.elementGroups.collisionBox = new ElementGroups(this.buffers.collisionBoxVertex); - var group = this.makeRoomFor('collisionBox', 0); - var angle = -collisionTile.angle; - var yStretch = collisionTile.yStretch; - - for (var j = 0; j < this.symbolInstances.length; j++) { - for (var i = 0; i < 2; i++) { - var feature = this.symbolInstances[j][i === 0 ? 'textCollisionFeature' : 'iconCollisionFeature']; - if (!feature) continue; - var boxes = feature.boxes; - - for (var b = 0; b < boxes.length; b++) { - var box = boxes[b]; - var anchorPoint = box.anchorPoint; - - var tl = new Point(box.x1, box.y1 * yStretch)._rotate(angle); - var tr = new Point(box.x2, box.y1 * yStretch)._rotate(angle); - var bl = new Point(box.x1, box.y2 * yStretch)._rotate(angle); - var br = new Point(box.x2, box.y2 * yStretch)._rotate(angle); - - var maxZoom = Math.max(0, Math.min(25, this.zoom + Math.log(box.maxScale) / Math.LN2)); - var placementZoom = Math.max(0, Math.min(25, this.zoom + Math.log(box.placementScale) / Math.LN2)); - - this.addCollisionBoxVertex(anchorPoint, tl, maxZoom, placementZoom); - this.addCollisionBoxVertex(anchorPoint, tr, maxZoom, placementZoom); - this.addCollisionBoxVertex(anchorPoint, tr, maxZoom, placementZoom); - this.addCollisionBoxVertex(anchorPoint, br, maxZoom, placementZoom); - this.addCollisionBoxVertex(anchorPoint, br, maxZoom, placementZoom); - this.addCollisionBoxVertex(anchorPoint, bl, maxZoom, placementZoom); - this.addCollisionBoxVertex(anchorPoint, bl, maxZoom, placementZoom); - this.addCollisionBoxVertex(anchorPoint, tl, maxZoom, placementZoom); - group.vertexLength += 8; - } - } - } +/** + * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) + * + * @param {mat2d} a The first matrix. + * @param {mat2d} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ +mat2d.exactEquals = function (a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5]; }; -function SymbolInstance(anchor, line, shapedText, shapedIcon, layout, addToBuffers, index, - textBoxScale, textPadding, textAlongLine, - iconBoxScale, iconPadding, iconAlongLine) { - - this.x = anchor.x; - this.y = anchor.y; - this.index = index; - this.hasText = !!shapedText; - this.hasIcon = !!shapedIcon; - - if (this.hasText) { - this.glyphQuads = addToBuffers ? getGlyphQuads(anchor, shapedText, textBoxScale, line, layout, textAlongLine) : []; - this.textCollisionFeature = new CollisionFeature(line, anchor, shapedText, textBoxScale, textPadding, textAlongLine, false); - } - - if (this.hasIcon) { - this.iconQuads = addToBuffers ? getIconQuads(anchor, shapedIcon, iconBoxScale, line, layout, iconAlongLine) : []; - this.iconCollisionFeature = new CollisionFeature(line, anchor, shapedIcon, iconBoxScale, iconPadding, iconAlongLine, true); - } -} - -},{"../symbol/anchor":71,"../symbol/clip_line":73,"../symbol/collision_feature":75,"../symbol/get_anchors":77,"../symbol/mergelines":80,"../symbol/quads":81,"../symbol/resolve_text":82,"../symbol/shaping":83,"../util/token":112,"../util/util":113,"./bucket":16,"./buffer":17,"./element_groups":19,"./load_geometry":23,"point-geometry":162}],25:[function(require,module,exports){ -'use strict'; - -module.exports = Coordinate; - /** - * A coordinate is a column, row, zoom combination, often used - * as the data component of a tile. + * Returns whether or not the matrices have approximately the same elements in the same position. * - * @param {number} column - * @param {number} row - * @param {number} zoom - * @private + * @param {mat2d} a The first matrix. + * @param {mat2d} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. */ -function Coordinate(column, row, zoom) { - this.column = column; - this.row = row; - this.zoom = zoom; -} - -Coordinate.prototype = { +mat2d.equals = function (a, b) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5]; + var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5]; + return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && + Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) && + Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) && + Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) && + Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) && + Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5))); +}; - /** - * Create a clone of this coordinate that can be mutated without - * changing the original coordinate - * - * @returns {Coordinate} clone - * @private - * var coord = new Coordinate(0, 0, 0); - * var c2 = coord.clone(); - * // since coord is cloned, modifying a property of c2 does - * // not modify it. - * c2.zoom = 2; - */ - clone: function() { - return new Coordinate(this.column, this.row, this.zoom); - }, +module.exports = mat2d; - /** - * Zoom this coordinate to a given zoom level. This returns a new - * coordinate object, not mutating the old one. - * - * @param {number} zoom - * @returns {Coordinate} zoomed coordinate - * @private - * @example - * var coord = new Coordinate(0, 0, 0); - * var c2 = coord.zoomTo(1); - * c2 // equals new Coordinate(0, 0, 1); - */ - zoomTo: function(zoom) { return this.clone()._zoomTo(zoom); }, - - /** - * Subtract the column and row values of this coordinate from those - * of another coordinate. The other coordinat will be zoomed to the - * same level as `this` before the subtraction occurs - * - * @param {Coordinate} c other coordinate - * @returns {Coordinate} result - * @private - */ - sub: function(c) { return this.clone()._sub(c); }, - - _zoomTo: function(zoom) { - var scale = Math.pow(2, zoom - this.zoom); - this.column *= scale; - this.row *= scale; - this.zoom = zoom; - return this; - }, +},{"./common.js":30}],33:[function(require,module,exports){ +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - _sub: function(c) { - c = c.zoomTo(this.zoom); - this.column -= c.column; - this.row -= c.row; - return this; - } -}; +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: -},{}],26:[function(require,module,exports){ -'use strict'; +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. -module.exports = LngLat; +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. */ -var wrap = require('../util/util').wrap; +var glMatrix = require("./common.js"); /** - * Create a longitude, latitude object from a given longitude and latitude pair in degrees. - * Mapbox GL uses Longitude, Latitude coordinate order to match GeoJSON. - * - * Note that any Mapbox GL method that accepts a `LngLat` object can also accept an - * `Array` and will perform an implicit conversion. The following lines are equivalent: - ``` - map.setCenter([-73.9749, 40.7736]); - map.setCenter( new mapboxgl.LngLat(-73.9749, 40.7736) ); - ``` - * - * @class LngLat - * @classdesc A representation of a longitude, latitude point, in degrees. - * @param {number} lng longitude - * @param {number} lat latitude - * @example - * var ll = new mapboxgl.LngLat(-73.9749, 40.7736); + * @class 3x3 Matrix + * @name mat3 */ -function LngLat(lng, lat) { - if (isNaN(lng) || isNaN(lat)) { - throw new Error('Invalid LngLat object: (' + lng + ', ' + lat + ')'); - } - this.lng = +lng; - this.lat = +lat; - if (this.lat > 90 || this.lat < -90) { - throw new Error('Invalid LngLat latitude value: must be between -90 and 90'); - } -} +var mat3 = {}; /** - * Return a new `LngLat` object whose longitude is wrapped to the range (-180, 180). + * Creates a new identity mat3 * - * @returns {LngLat} wrapped LngLat object - * @example - * var ll = new mapboxgl.LngLat(286.0251, 40.7736); - * var wrapped = ll.wrap(); - * wrapped.lng; // = -73.9749 + * @returns {mat3} a new 3x3 matrix */ -LngLat.prototype.wrap = function () { - return new LngLat(wrap(this.lng, -180, 180), this.lat); +mat3.create = function() { + var out = new glMatrix.ARRAY_TYPE(9); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 1; + out[5] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; }; /** - * Return a `LngLat` as an array + * Copies the upper-left 3x3 values into the given mat3. * - * @returns {array} [lng, lat] - * @example - * var ll = new mapboxgl.LngLat(-73.9749, 40.7736); - * ll.toArray(); // = [-73.9749, 40.7736] + * @param {mat3} out the receiving 3x3 matrix + * @param {mat4} a the source 4x4 matrix + * @returns {mat3} out */ -LngLat.prototype.toArray = function () { - return [this.lng, this.lat]; +mat3.fromMat4 = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[4]; + out[4] = a[5]; + out[5] = a[6]; + out[6] = a[8]; + out[7] = a[9]; + out[8] = a[10]; + return out; }; /** - * Return a `LngLat` as a string + * Creates a new mat3 initialized with values from an existing matrix * - * @returns {string} "LngLat(lng, lat)" - * @example - * var ll = new mapboxgl.LngLat(-73.9749, 40.7736); - * ll.toString(); // = "LngLat(-73.9749, 40.7736)" + * @param {mat3} a matrix to clone + * @returns {mat3} a new 3x3 matrix */ -LngLat.prototype.toString = function () { - return 'LngLat(' + this.lng + ', ' + this.lat + ')'; +mat3.clone = function(a) { + var out = new glMatrix.ARRAY_TYPE(9); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; }; /** - * Convert an array to a `LngLat` object, or return an existing `LngLat` object - * unchanged. + * Copy the values from one mat3 to another * - * @param {Array|LngLat} input `input` to convert - * @returns {LngLat} LngLat object or original input - * @example - * var arr = [-73.9749, 40.7736]; - * var ll = mapboxgl.LngLat.convert(arr); - * ll; // = LngLat {lng: -73.9749, lat: 40.7736} + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out */ -LngLat.convert = function (input) { - if (input instanceof LngLat) { - return input; - } - if (Array.isArray(input)) { - return new LngLat(input[0], input[1]); - } - return input; -}; +mat3.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; +}; -},{"../util/util":113}],27:[function(require,module,exports){ -'use strict'; +/** + * Create a new mat3 with the given values + * + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m02 Component in column 0, row 2 position (index 2) + * @param {Number} m10 Component in column 1, row 0 position (index 3) + * @param {Number} m11 Component in column 1, row 1 position (index 4) + * @param {Number} m12 Component in column 1, row 2 position (index 5) + * @param {Number} m20 Component in column 2, row 0 position (index 6) + * @param {Number} m21 Component in column 2, row 1 position (index 7) + * @param {Number} m22 Component in column 2, row 2 position (index 8) + * @returns {mat3} A new mat3 + */ +mat3.fromValues = function(m00, m01, m02, m10, m11, m12, m20, m21, m22) { + var out = new glMatrix.ARRAY_TYPE(9); + out[0] = m00; + out[1] = m01; + out[2] = m02; + out[3] = m10; + out[4] = m11; + out[5] = m12; + out[6] = m20; + out[7] = m21; + out[8] = m22; + return out; +}; -module.exports = LngLatBounds; +/** + * Set the components of a mat3 to the given values + * + * @param {mat3} out the receiving matrix + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m02 Component in column 0, row 2 position (index 2) + * @param {Number} m10 Component in column 1, row 0 position (index 3) + * @param {Number} m11 Component in column 1, row 1 position (index 4) + * @param {Number} m12 Component in column 1, row 2 position (index 5) + * @param {Number} m20 Component in column 2, row 0 position (index 6) + * @param {Number} m21 Component in column 2, row 1 position (index 7) + * @param {Number} m22 Component in column 2, row 2 position (index 8) + * @returns {mat3} out + */ +mat3.set = function(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) { + out[0] = m00; + out[1] = m01; + out[2] = m02; + out[3] = m10; + out[4] = m11; + out[5] = m12; + out[6] = m20; + out[7] = m21; + out[8] = m22; + return out; +}; -var LngLat = require('./lng_lat'); +/** + * Set a mat3 to the identity matrix + * + * @param {mat3} out the receiving matrix + * @returns {mat3} out + */ +mat3.identity = function(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 1; + out[5] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; +}; /** - * Creates a bounding box from the given pair of points. If parameteres are omitted, a `null` bounding box is created. + * Transpose the values of a mat3 * - * @class LngLatBounds - * @classdesc A representation of rectangular box on the earth, defined by its southwest and northeast points in longitude and latitude. - * @param {LngLat} sw southwest - * @param {LngLat} ne northeast - * @example - * var sw = new mapboxgl.LngLat(-73.9876, 40.7661); - * var ne = new mapboxgl.LngLat(-73.9397, 40.8002); - * var llb = new mapboxgl.LngLatBounds(sw, ne); + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out */ -function LngLatBounds(sw, ne) { - if (!sw) { - return; - } else if (ne) { - this.extend(sw).extend(ne); - } else if (sw.length === 4) { - this.extend([sw[0], sw[1]]).extend([sw[2], sw[3]]); +mat3.transpose = function(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (out === a) { + var a01 = a[1], a02 = a[2], a12 = a[5]; + out[1] = a[3]; + out[2] = a[6]; + out[3] = a01; + out[5] = a[7]; + out[6] = a02; + out[7] = a12; } else { - this.extend(sw[0]).extend(sw[1]); + out[0] = a[0]; + out[1] = a[3]; + out[2] = a[6]; + out[3] = a[1]; + out[4] = a[4]; + out[5] = a[7]; + out[6] = a[2]; + out[7] = a[5]; + out[8] = a[8]; } -} + + return out; +}; -LngLatBounds.prototype = { +/** + * Inverts a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ +mat3.invert = function(out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8], - /** - * Extend the bounds to include a given LngLat or LngLatBounds. - * - * @param {LngLat|LngLatBounds} obj object to extend to - * @returns {LngLatBounds} `this` - */ - extend: function(obj) { - var sw = this._sw, - ne = this._ne, - sw2, ne2; + b01 = a22 * a11 - a12 * a21, + b11 = -a22 * a10 + a12 * a20, + b21 = a21 * a10 - a11 * a20, - if (obj instanceof LngLat) { - sw2 = obj; - ne2 = obj; + // Calculate the determinant + det = a00 * b01 + a01 * b11 + a02 * b21; - } else if (obj instanceof LngLatBounds) { - sw2 = obj._sw; - ne2 = obj._ne; + if (!det) { + return null; + } + det = 1.0 / det; - if (!sw2 || !ne2) return this; + out[0] = b01 * det; + out[1] = (-a22 * a01 + a02 * a21) * det; + out[2] = (a12 * a01 - a02 * a11) * det; + out[3] = b11 * det; + out[4] = (a22 * a00 - a02 * a20) * det; + out[5] = (-a12 * a00 + a02 * a10) * det; + out[6] = b21 * det; + out[7] = (-a21 * a00 + a01 * a20) * det; + out[8] = (a11 * a00 - a01 * a10) * det; + return out; +}; - } else { - return obj ? this.extend(LngLat.convert(obj) || LngLatBounds.convert(obj)) : this; - } +/** + * Calculates the adjugate of a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ +mat3.adjoint = function(out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8]; - if (!sw && !ne) { - this._sw = new LngLat(sw2.lng, sw2.lat); - this._ne = new LngLat(ne2.lng, ne2.lat); + out[0] = (a11 * a22 - a12 * a21); + out[1] = (a02 * a21 - a01 * a22); + out[2] = (a01 * a12 - a02 * a11); + out[3] = (a12 * a20 - a10 * a22); + out[4] = (a00 * a22 - a02 * a20); + out[5] = (a02 * a10 - a00 * a12); + out[6] = (a10 * a21 - a11 * a20); + out[7] = (a01 * a20 - a00 * a21); + out[8] = (a00 * a11 - a01 * a10); + return out; +}; - } else { - sw.lng = Math.min(sw2.lng, sw.lng); - sw.lat = Math.min(sw2.lat, sw.lat); - ne.lng = Math.max(ne2.lng, ne.lng); - ne.lat = Math.max(ne2.lat, ne.lat); - } +/** + * Calculates the determinant of a mat3 + * + * @param {mat3} a the source matrix + * @returns {Number} determinant of a + */ +mat3.determinant = function (a) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8]; - return this; - }, + return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20); +}; - /** - * Get the point equidistant from this box's corners - * @returns {LngLat} centerpoint - * @example - * var llb = new mapboxgl.LngLatBounds([-73.9876, 40.7661], [-73.9397, 40.8002]); - * llb.getCenter(); // = LngLat {lng: -73.96365, lat: 40.78315} - */ - getCenter: function() { - return new LngLat((this._sw.lng + this._ne.lng) / 2, (this._sw.lat + this._ne.lat) / 2); - }, +/** + * Multiplies two mat3's + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the first operand + * @param {mat3} b the second operand + * @returns {mat3} out + */ +mat3.multiply = function (out, a, b) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8], - /** - * Get southwest corner - * @returns {LngLat} southwest - */ - getSouthWest: function() { return this._sw; }, - - /** - * Get northeast corner - * @returns {LngLat} northeast - */ - getNorthEast: function() { return this._ne; }, - - /** - * Get northwest corner - * @returns {LngLat} northwest - */ - getNorthWest: function() { return new LngLat(this.getWest(), this.getNorth()); }, - - /** - * Get southeast corner - * @returns {LngLat} southeast - */ - getSouthEast: function() { return new LngLat(this.getEast(), this.getSouth()); }, - - /** - * Get west edge longitude - * @returns {number} west - */ - getWest: function() { return this._sw.lng; }, - - /** - * Get south edge latitude - * @returns {number} south - */ - getSouth: function() { return this._sw.lat; }, - - /** - * Get east edge longitude - * @returns {number} east - */ - getEast: function() { return this._ne.lng; }, - - /** - * Get north edge latitude - * @returns {number} north - */ - getNorth: function() { return this._ne.lat; }, - - /** - * Return a `LngLatBounds` as an array - * - * @returns {array} [lng, lat] - * @example - * var llb = new mapboxgl.LngLatBounds([-73.9876, 40.7661], [-73.9397, 40.8002]); - * llb.toArray(); // = [[-73.9876, 40.7661], [-73.9397, 40.8002]] - */ - toArray: function () { - return [this._sw.toArray(), this._ne.toArray()]; - }, + b00 = b[0], b01 = b[1], b02 = b[2], + b10 = b[3], b11 = b[4], b12 = b[5], + b20 = b[6], b21 = b[7], b22 = b[8]; - /** - * Return a `LngLatBounds` as a string - * - * @returns {string} "LngLatBounds(LngLat(lng, lat), LngLat(lng, lat))" - * @example - * var llb = new mapboxgl.LngLatBounds([-73.9876, 40.7661], [-73.9397, 40.8002]); - * llb.toString(); // = "LngLatBounds(LngLat(-73.9876, 40.7661), LngLat(-73.9397, 40.8002))" - */ - toString: function () { - return 'LngLatBounds(' + this._sw.toString() + ', ' + this._ne.toString() + ')'; - } + out[0] = b00 * a00 + b01 * a10 + b02 * a20; + out[1] = b00 * a01 + b01 * a11 + b02 * a21; + out[2] = b00 * a02 + b01 * a12 + b02 * a22; + + out[3] = b10 * a00 + b11 * a10 + b12 * a20; + out[4] = b10 * a01 + b11 * a11 + b12 * a21; + out[5] = b10 * a02 + b11 * a12 + b12 * a22; + + out[6] = b20 * a00 + b21 * a10 + b22 * a20; + out[7] = b20 * a01 + b21 * a11 + b22 * a21; + out[8] = b20 * a02 + b21 * a12 + b22 * a22; + return out; }; /** - * Convert an array to a `LngLatBounds` object, or return an existing - * `LngLatBounds` object unchanged. - * - * Calls `LngLat#convert` internally to convert arrays as `LngLat` values. - * - * @param {LngLatBounds|Array|Array>} input input to convert to a LngLatBounds - * @returns {LngLatBounds} LngLatBounds object or original input - * @example - * var arr = [[-73.9876, 40.7661], [-73.9397, 40.8002]]; - * var llb = mapboxgl.LngLatBounds.convert(arr); - * llb; // = LngLatBounds {_sw: LngLat {lng: -73.9876, lat: 40.7661}, _ne: LngLat {lng: -73.9397, lat: 40.8002}} + * Alias for {@link mat3.multiply} + * @function */ -LngLatBounds.convert = function (input) { - if (!input || input instanceof LngLatBounds) return input; - return new LngLatBounds(input); -}; +mat3.mul = mat3.multiply; -},{"./lng_lat":26}],28:[function(require,module,exports){ -'use strict'; +/** + * Translate a mat3 by the given vector + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to translate + * @param {vec2} v vector to translate by + * @returns {mat3} out + */ +mat3.translate = function(out, a, v) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8], + x = v[0], y = v[1]; -var LngLat = require('./lng_lat'), - Point = require('point-geometry'), - Coordinate = require('./coordinate'), - wrap = require('../util/util').wrap, - interp = require('../util/interpolate'), - glmatrix = require('gl-matrix'); + out[0] = a00; + out[1] = a01; + out[2] = a02; -var vec4 = glmatrix.vec4, - mat4 = glmatrix.mat4, - mat2 = glmatrix.mat2; + out[3] = a10; + out[4] = a11; + out[5] = a12; -module.exports = Transform; + out[6] = x * a00 + y * a10 + a20; + out[7] = x * a01 + y * a11 + a21; + out[8] = x * a02 + y * a12 + a22; + return out; +}; -/* - * A single transform, generally used for a single tile to be - * scaled, rotated, and zoomed. +/** + * Rotates a mat3 by the given angle * - * @param {number} minZoom - * @param {number} maxZoom - * @private + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat3} out */ -function Transform(minZoom, maxZoom) { - this.tileSize = 512; // constant +mat3.rotate = function (out, a, rad) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8], - this._minZoom = minZoom || 0; - this._maxZoom = maxZoom || 22; + s = Math.sin(rad), + c = Math.cos(rad); - this.latRange = [-85.05113, 85.05113]; + out[0] = c * a00 + s * a10; + out[1] = c * a01 + s * a11; + out[2] = c * a02 + s * a12; - this.width = 0; - this.height = 0; - this._center = new LngLat(0, 0); - this.zoom = 0; - this.angle = 0; - this._altitude = 1.5; - this._pitch = 0; - this._unmodified = true; -} - -Transform.prototype = { - get minZoom() { return this._minZoom; }, - set minZoom(zoom) { - if (this._minZoom === zoom) return; - this._minZoom = zoom; - this.zoom = Math.max(this.zoom, zoom); - }, - - get maxZoom() { return this._maxZoom; }, - set maxZoom(zoom) { - if (this._maxZoom === zoom) return; - this._maxZoom = zoom; - this.zoom = Math.min(this.zoom, zoom); - }, + out[3] = c * a10 - s * a00; + out[4] = c * a11 - s * a01; + out[5] = c * a12 - s * a02; - get worldSize() { - return this.tileSize * this.scale; - }, + out[6] = a20; + out[7] = a21; + out[8] = a22; + return out; +}; - get centerPoint() { - return this.size._div(2); - }, +/** + * Scales the mat3 by the dimensions in the given vec2 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to rotate + * @param {vec2} v the vec2 to scale the matrix by + * @returns {mat3} out + **/ +mat3.scale = function(out, a, v) { + var x = v[0], y = v[1]; - get size() { - return new Point(this.width, this.height); - }, + out[0] = x * a[0]; + out[1] = x * a[1]; + out[2] = x * a[2]; - get bearing() { - return -this.angle / Math.PI * 180; - }, - set bearing(bearing) { - var b = -wrap(bearing, -180, 180) * Math.PI / 180; - if (this.angle === b) return; - this._unmodified = false; - this.angle = b; - this._calcProjMatrix(); + out[3] = y * a[3]; + out[4] = y * a[4]; + out[5] = y * a[5]; - // 2x2 matrix for rotating points - this.rotationMatrix = mat2.create(); - mat2.rotate(this.rotationMatrix, this.rotationMatrix, this.angle); - }, + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; +}; - get pitch() { - return this._pitch / Math.PI * 180; - }, - set pitch(pitch) { - var p = Math.min(60, pitch) / 180 * Math.PI; - if (this._pitch === p) return; - this._unmodified = false; - this._pitch = p; - this._calcProjMatrix(); - }, +/** + * Creates a matrix from a vector translation + * This is equivalent to (but much faster than): + * + * mat3.identity(dest); + * mat3.translate(dest, dest, vec); + * + * @param {mat3} out mat3 receiving operation result + * @param {vec2} v Translation vector + * @returns {mat3} out + */ +mat3.fromTranslation = function(out, v) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 1; + out[5] = 0; + out[6] = v[0]; + out[7] = v[1]; + out[8] = 1; + return out; +} - get altitude() { - return this._altitude; - }, - set altitude(altitude) { - var a = Math.max(0.75, altitude); - if (this._altitude === a) return; - this._unmodified = false; - this._altitude = a; - this._calcProjMatrix(); - }, +/** + * Creates a matrix from a given angle + * This is equivalent to (but much faster than): + * + * mat3.identity(dest); + * mat3.rotate(dest, dest, rad); + * + * @param {mat3} out mat3 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat3} out + */ +mat3.fromRotation = function(out, rad) { + var s = Math.sin(rad), c = Math.cos(rad); - get zoom() { return this._zoom; }, - set zoom(zoom) { - var z = Math.min(Math.max(zoom, this.minZoom), this.maxZoom); - if (this._zoom === z) return; - this._unmodified = false; - this._zoom = z; - this.scale = this.zoomScale(z); - this.tileZoom = Math.floor(z); - this.zoomFraction = z - this.tileZoom; - this._calcProjMatrix(); - this._constrain(); - }, + out[0] = c; + out[1] = s; + out[2] = 0; - get center() { return this._center; }, - set center(center) { - if (center.lat === this._center.lat && center.lng === this._center.lng) return; - this._unmodified = false; - this._center = center; - this._calcProjMatrix(); - this._constrain(); - }, + out[3] = -s; + out[4] = c; + out[5] = 0; - resize: function(width, height) { - this.width = width; - this.height = height; + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; +} - // The extrusion matrix - this.exMatrix = mat4.create(); - mat4.ortho(this.exMatrix, 0, width, height, 0, 0, -1); +/** + * Creates a matrix from a vector scaling + * This is equivalent to (but much faster than): + * + * mat3.identity(dest); + * mat3.scale(dest, dest, vec); + * + * @param {mat3} out mat3 receiving operation result + * @param {vec2} v Scaling vector + * @returns {mat3} out + */ +mat3.fromScaling = function(out, v) { + out[0] = v[0]; + out[1] = 0; + out[2] = 0; - this._calcProjMatrix(); - this._constrain(); - }, + out[3] = 0; + out[4] = v[1]; + out[5] = 0; - get unmodified() { return this._unmodified; }, + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; +} - zoomScale: function(zoom) { return Math.pow(2, zoom); }, - scaleZoom: function(scale) { return Math.log(scale) / Math.LN2; }, +/** + * Copies the values from a mat2d into a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat2d} a the matrix to copy + * @returns {mat3} out + **/ +mat3.fromMat2d = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = 0; - project: function(lnglat, worldSize) { - return new Point( - this.lngX(lnglat.lng, worldSize), - this.latY(lnglat.lat, worldSize)); - }, + out[3] = a[2]; + out[4] = a[3]; + out[5] = 0; - unproject: function(point, worldSize) { - return new LngLat( - this.xLng(point.x, worldSize), - this.yLat(point.y, worldSize)); - }, + out[6] = a[4]; + out[7] = a[5]; + out[8] = 1; + return out; +}; - get x() { return this.lngX(this.center.lng); }, - get y() { return this.latY(this.center.lat); }, +/** +* Calculates a 3x3 matrix from the given quaternion +* +* @param {mat3} out mat3 receiving operation result +* @param {quat} q Quaternion to create matrix from +* +* @returns {mat3} out +*/ +mat3.fromQuat = function (out, q) { + var x = q[0], y = q[1], z = q[2], w = q[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, - get point() { return new Point(this.x, this.y); }, + xx = x * x2, + yx = y * x2, + yy = y * y2, + zx = z * x2, + zy = z * y2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; - /** - * latitude to absolute x coord - * @param {number} lon - * @param {number} [worldSize=this.worldSize] - * @returns {number} pixel coordinate - * @private - */ - lngX: function(lng, worldSize) { - return (180 + lng) * (worldSize || this.worldSize) / 360; - }, - /** - * latitude to absolute y coord - * @param {number} lat - * @param {number} [worldSize=this.worldSize] - * @returns {number} pixel coordinate - * @private - */ - latY: function(lat, worldSize) { - var y = 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360)); - return (180 - y) * (worldSize || this.worldSize) / 360; - }, + out[0] = 1 - yy - zz; + out[3] = yx - wz; + out[6] = zx + wy; - xLng: function(x, worldSize) { - return x * 360 / (worldSize || this.worldSize) - 180; - }, - yLat: function(y, worldSize) { - var y2 = 180 - y * 360 / (worldSize || this.worldSize); - return 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90; - }, + out[1] = yx + wz; + out[4] = 1 - xx - zz; + out[7] = zy - wx; - panBy: function(offset) { - var point = this.centerPoint._add(offset); - this.center = this.pointLocation(point); - }, + out[2] = zx - wy; + out[5] = zy + wx; + out[8] = 1 - xx - yy; - setLocationAtPoint: function(lnglat, point) { - var c = this.locationCoordinate(lnglat); - var coordAtPoint = this.pointCoordinate(point); - var coordCenter = this.pointCoordinate(this.centerPoint); - var translate = coordAtPoint._sub(c); - this._unmodified = false; - this.center = this.coordinateLocation(coordCenter._sub(translate)); - }, + return out; +}; - setZoomAround: function(zoom, center) { - var p; - if (center) p = this.locationPoint(center); - this.zoom = zoom; - if (center) this.setLocationAtPoint(center, p); - }, +/** +* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix +* +* @param {mat3} out mat3 receiving operation result +* @param {mat4} a Mat4 to derive the normal matrix from +* +* @returns {mat3} out +*/ +mat3.normalFromMat4 = function (out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], - setBearingAround: function(bearing, center) { - var p; - if (center) p = this.locationPoint(center); - this.bearing = bearing; - if (center) this.setLocationAtPoint(center, p); - }, - - /** - * Given a location, return the screen point that corresponds to it - * @param {LngLat} lnglat location - * @returns {Point} screen point - * @private - */ - locationPoint: function(lnglat) { - return this.coordinatePoint(this.locationCoordinate(lnglat)); - }, - - /** - * Given a point on screen, return its lnglat - * @param {Point} p screen point - * @returns {LngLat} lnglat location - * @private - */ - pointLocation: function(p) { - return this.coordinateLocation(this.pointCoordinate(p)); - }, - - /** - * Given a geographical lnglat, return an unrounded - * coordinate that represents it at this transform's zoom level and - * worldsize. - * @param {LngLat} lnglat - * @returns {Coordinate} - * @private - */ - locationCoordinate: function(lnglat) { - var k = this.zoomScale(this.tileZoom) / this.worldSize, - ll = LngLat.convert(lnglat); - - return new Coordinate( - this.lngX(ll.lng) * k, - this.latY(ll.lat) * k, - this.tileZoom); - }, - - /** - * Given a Coordinate, return its geographical position. - * @param {Coordinate} coord - * @returns {LngLat} lnglat - * @private - */ - coordinateLocation: function(coord) { - var worldSize = this.zoomScale(coord.zoom); - return new LngLat( - this.xLng(coord.column, worldSize), - this.yLat(coord.row, worldSize)); - }, - - pointCoordinate: function(p, targetZ) { - - if (targetZ === undefined) targetZ = 0; - - var matrix = this.coordinatePointMatrix(this.tileZoom); - mat4.invert(matrix, matrix); - - if (!matrix) throw new Error("failed to invert matrix"); - - // since we don't know the correct projected z value for the point, - // unproject two points to get a line and then find the point on that - // line with z=0 - - var coord0 = [p.x, p.y, 0, 1]; - var coord1 = [p.x, p.y, 1, 1]; - - vec4.transformMat4(coord0, coord0, matrix); - vec4.transformMat4(coord1, coord1, matrix); - - var w0 = coord0[3]; - var w1 = coord1[3]; - var x0 = coord0[0] / w0; - var x1 = coord1[0] / w1; - var y0 = coord0[1] / w0; - var y1 = coord1[1] / w1; - var z0 = coord0[2] / w0; - var z1 = coord1[2] / w1; - - - var t = z0 === z1 ? 0 : (targetZ - z0) / (z1 - z0); - - return new Coordinate( - interp(x0, x1, t), - interp(y0, y1, t), - this.tileZoom); - }, - - /** - * Given a coordinate, return the screen point that corresponds to it - * @param {Coordinate} coord - * @returns {Point} screen point - * @private - */ - coordinatePoint: function(coord) { - var matrix = this.coordinatePointMatrix(coord.zoom); - var p = [coord.column, coord.row, 0, 1]; - vec4.transformMat4(p, p, matrix); - return new Point(p[0] / p[3], p[1] / p[3]); - }, - - coordinatePointMatrix: function(z) { - var proj = mat4.copy(new Float64Array(16), this.projMatrix); - var scale = this.worldSize / this.zoomScale(z); - mat4.scale(proj, proj, [scale, scale, 1]); - mat4.multiply(proj, this.getPixelMatrix(), proj); - return proj; - }, - - /** - * converts gl coordinates -1..1 to pixels 0..width - * @returns {Object} matrix - * @private - */ - getPixelMatrix: function() { - var m = mat4.create(); - mat4.scale(m, m, [this.width / 2, -this.height / 2, 1]); - mat4.translate(m, m, [1, -1, 0]); - return m; - }, - - _constrain: function() { - if (!this.center || !this.width || !this.height || this._constraining) return; - - this._constraining = true; - - var minY, maxY, minX, maxX, sy, sx, x2, y2, - size = this.size, - unmodified = this._unmodified; - - if (this.latRange) { - minY = this.latY(this.latRange[1]); - maxY = this.latY(this.latRange[0]); - sy = maxY - minY < size.y ? size.y / (maxY - minY) : 0; - } - - if (this.lngRange) { - minX = this.lngX(this.lngRange[0]); - maxX = this.lngX(this.lngRange[1]); - sx = maxX - minX < size.x ? size.x / (maxX - minX) : 0; - } - - // how much the map should scale to fit the screen into given latitude/longitude ranges - var s = Math.max(sx || 0, sy || 0); - - if (s) { - this.center = this.unproject(new Point( - sx ? (maxX + minX) / 2 : this.x, - sy ? (maxY + minY) / 2 : this.y)); - this.zoom += this.scaleZoom(s); - this._unmodified = unmodified; - this._constraining = false; - return; - } - - if (this.latRange) { - var y = this.y, - h2 = size.y / 2; - - if (y - h2 < minY) y2 = minY + h2; - if (y + h2 > maxY) y2 = maxY - h2; - } - - if (this.lngRange) { - var x = this.x, - w2 = size.x / 2; - - if (x - w2 < minX) x2 = minX + w2; - if (x + w2 > maxX) x2 = maxX - w2; - } - - // pan the map if the screen goes off the range - if (x2 !== undefined || y2 !== undefined) { - this.center = this.unproject(new Point( - x2 !== undefined ? x2 : this.x, - y2 !== undefined ? y2 : this.y)); - } - - this._unmodified = unmodified; - this._constraining = false; - }, - - _calcProjMatrix: function() { - var m = new Float64Array(16); - - // Find the distance from the center point to the center top in altitude units using law of sines. - var halfFov = Math.atan(0.5 / this.altitude); - var topHalfSurfaceDistance = Math.sin(halfFov) * this.altitude / Math.sin(Math.PI / 2 - this._pitch - halfFov); + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32, - // Calculate z value of the farthest fragment that should be rendered. - var farZ = Math.cos(Math.PI / 2 - this._pitch) * topHalfSurfaceDistance + this.altitude; + // Calculate the determinant + det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; - mat4.perspective(m, 2 * Math.atan((this.height / 2) / this.altitude), this.width / this.height, 0.1, farZ); + if (!det) { + return null; + } + det = 1.0 / det; - mat4.translate(m, m, [0, 0, -this.altitude]); + out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det; - // After the rotateX, z values are in pixel units. Convert them to - // altitude unites. 1 altitude unit = the screen height. - mat4.scale(m, m, [1, -1, 1 / this.height]); + out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det; - mat4.rotateX(m, m, this._pitch); - mat4.rotateZ(m, m, this.angle); - mat4.translate(m, m, [-this.x, -this.y, 0]); + out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det; - this.projMatrix = m; - } + return out; }; -},{"../util/interpolate":109,"../util/util":113,"./coordinate":25,"./lng_lat":26,"gl-matrix":123,"point-geometry":162}],29:[function(require,module,exports){ -'use strict'; - -// Font data From Hershey Simplex Font -// http://paulbourke.net/dataformats/hershey/ -var simplexFont = { - " ": [16, []], - "!": [10, [5, 21, 5, 7, -1, -1, 5, 2, 4, 1, 5, 0, 6, 1, 5, 2]], - "\"": [16, [4, 21, 4, 14, -1, -1, 12, 21, 12, 14]], - "#": [21, [11, 25, 4, -7, -1, -1, 17, 25, 10, -7, -1, -1, 4, 12, 18, 12, -1, -1, 3, 6, 17, 6]], - "$": [20, [8, 25, 8, -4, -1, -1, 12, 25, 12, -4, -1, -1, 17, 18, 15, 20, 12, 21, 8, 21, 5, 20, 3, 18, 3, 16, 4, 14, 5, 13, 7, 12, 13, 10, 15, 9, 16, 8, 17, 6, 17, 3, 15, 1, 12, 0, 8, 0, 5, 1, 3, 3]], - "%": [24, [21, 21, 3, 0, -1, -1, 8, 21, 10, 19, 10, 17, 9, 15, 7, 14, 5, 14, 3, 16, 3, 18, 4, 20, 6, 21, 8, 21, 10, 20, 13, 19, 16, 19, 19, 20, 21, 21, -1, -1, 17, 7, 15, 6, 14, 4, 14, 2, 16, 0, 18, 0, 20, 1, 21, 3, 21, 5, 19, 7, 17, 7]], - "&": [26, [23, 12, 23, 13, 22, 14, 21, 14, 20, 13, 19, 11, 17, 6, 15, 3, 13, 1, 11, 0, 7, 0, 5, 1, 4, 2, 3, 4, 3, 6, 4, 8, 5, 9, 12, 13, 13, 14, 14, 16, 14, 18, 13, 20, 11, 21, 9, 20, 8, 18, 8, 16, 9, 13, 11, 10, 16, 3, 18, 1, 20, 0, 22, 0, 23, 1, 23, 2]], - "'": [10, [5, 19, 4, 20, 5, 21, 6, 20, 6, 18, 5, 16, 4, 15]], - "(": [14, [11, 25, 9, 23, 7, 20, 5, 16, 4, 11, 4, 7, 5, 2, 7, -2, 9, -5, 11, -7]], - ")": [14, [3, 25, 5, 23, 7, 20, 9, 16, 10, 11, 10, 7, 9, 2, 7, -2, 5, -5, 3, -7]], - "*": [16, [8, 21, 8, 9, -1, -1, 3, 18, 13, 12, -1, -1, 13, 18, 3, 12]], - "+": [26, [13, 18, 13, 0, -1, -1, 4, 9, 22, 9]], - ",": [10, [6, 1, 5, 0, 4, 1, 5, 2, 6, 1, 6, -1, 5, -3, 4, -4]], - "-": [26, [4, 9, 22, 9]], - ".": [10, [5, 2, 4, 1, 5, 0, 6, 1, 5, 2]], - "/": [22, [20, 25, 2, -7]], - "0": [20, [9, 21, 6, 20, 4, 17, 3, 12, 3, 9, 4, 4, 6, 1, 9, 0, 11, 0, 14, 1, 16, 4, 17, 9, 17, 12, 16, 17, 14, 20, 11, 21, 9, 21]], - "1": [20, [6, 17, 8, 18, 11, 21, 11, 0]], - "2": [20, [4, 16, 4, 17, 5, 19, 6, 20, 8, 21, 12, 21, 14, 20, 15, 19, 16, 17, 16, 15, 15, 13, 13, 10, 3, 0, 17, 0]], - "3": [20, [5, 21, 16, 21, 10, 13, 13, 13, 15, 12, 16, 11, 17, 8, 17, 6, 16, 3, 14, 1, 11, 0, 8, 0, 5, 1, 4, 2, 3, 4]], - "4": [20, [13, 21, 3, 7, 18, 7, -1, -1, 13, 21, 13, 0]], - "5": [20, [15, 21, 5, 21, 4, 12, 5, 13, 8, 14, 11, 14, 14, 13, 16, 11, 17, 8, 17, 6, 16, 3, 14, 1, 11, 0, 8, 0, 5, 1, 4, 2, 3, 4]], - "6": [20, [16, 18, 15, 20, 12, 21, 10, 21, 7, 20, 5, 17, 4, 12, 4, 7, 5, 3, 7, 1, 10, 0, 11, 0, 14, 1, 16, 3, 17, 6, 17, 7, 16, 10, 14, 12, 11, 13, 10, 13, 7, 12, 5, 10, 4, 7]], - "7": [20, [17, 21, 7, 0, -1, -1, 3, 21, 17, 21]], - "8": [20, [8, 21, 5, 20, 4, 18, 4, 16, 5, 14, 7, 13, 11, 12, 14, 11, 16, 9, 17, 7, 17, 4, 16, 2, 15, 1, 12, 0, 8, 0, 5, 1, 4, 2, 3, 4, 3, 7, 4, 9, 6, 11, 9, 12, 13, 13, 15, 14, 16, 16, 16, 18, 15, 20, 12, 21, 8, 21]], - "9": [20, [16, 14, 15, 11, 13, 9, 10, 8, 9, 8, 6, 9, 4, 11, 3, 14, 3, 15, 4, 18, 6, 20, 9, 21, 10, 21, 13, 20, 15, 18, 16, 14, 16, 9, 15, 4, 13, 1, 10, 0, 8, 0, 5, 1, 4, 3]], - ":": [10, [5, 14, 4, 13, 5, 12, 6, 13, 5, 14, -1, -1, 5, 2, 4, 1, 5, 0, 6, 1, 5, 2]], - ";": [10, [5, 14, 4, 13, 5, 12, 6, 13, 5, 14, -1, -1, 6, 1, 5, 0, 4, 1, 5, 2, 6, 1, 6, -1, 5, -3, 4, -4]], - "<": [24, [20, 18, 4, 9, 20, 0]], - "=": [26, [4, 12, 22, 12, -1, -1, 4, 6, 22, 6]], - ">": [24, [4, 18, 20, 9, 4, 0]], - "?": [18, [3, 16, 3, 17, 4, 19, 5, 20, 7, 21, 11, 21, 13, 20, 14, 19, 15, 17, 15, 15, 14, 13, 13, 12, 9, 10, 9, 7, -1, -1, 9, 2, 8, 1, 9, 0, 10, 1, 9, 2]], - "@": [27, [18, 13, 17, 15, 15, 16, 12, 16, 10, 15, 9, 14, 8, 11, 8, 8, 9, 6, 11, 5, 14, 5, 16, 6, 17, 8, -1, -1, 12, 16, 10, 14, 9, 11, 9, 8, 10, 6, 11, 5, -1, -1, 18, 16, 17, 8, 17, 6, 19, 5, 21, 5, 23, 7, 24, 10, 24, 12, 23, 15, 22, 17, 20, 19, 18, 20, 15, 21, 12, 21, 9, 20, 7, 19, 5, 17, 4, 15, 3, 12, 3, 9, 4, 6, 5, 4, 7, 2, 9, 1, 12, 0, 15, 0, 18, 1, 20, 2, 21, 3, -1, -1, 19, 16, 18, 8, 18, 6, 19, 5]], - "A": [18, [9, 21, 1, 0, -1, -1, 9, 21, 17, 0, -1, -1, 4, 7, 14, 7]], - "B": [21, [4, 21, 4, 0, -1, -1, 4, 21, 13, 21, 16, 20, 17, 19, 18, 17, 18, 15, 17, 13, 16, 12, 13, 11, -1, -1, 4, 11, 13, 11, 16, 10, 17, 9, 18, 7, 18, 4, 17, 2, 16, 1, 13, 0, 4, 0]], - "C": [21, [18, 16, 17, 18, 15, 20, 13, 21, 9, 21, 7, 20, 5, 18, 4, 16, 3, 13, 3, 8, 4, 5, 5, 3, 7, 1, 9, 0, 13, 0, 15, 1, 17, 3, 18, 5]], - "D": [21, [4, 21, 4, 0, -1, -1, 4, 21, 11, 21, 14, 20, 16, 18, 17, 16, 18, 13, 18, 8, 17, 5, 16, 3, 14, 1, 11, 0, 4, 0]], - "E": [19, [4, 21, 4, 0, -1, -1, 4, 21, 17, 21, -1, -1, 4, 11, 12, 11, -1, -1, 4, 0, 17, 0]], - "F": [18, [4, 21, 4, 0, -1, -1, 4, 21, 17, 21, -1, -1, 4, 11, 12, 11]], - "G": [21, [18, 16, 17, 18, 15, 20, 13, 21, 9, 21, 7, 20, 5, 18, 4, 16, 3, 13, 3, 8, 4, 5, 5, 3, 7, 1, 9, 0, 13, 0, 15, 1, 17, 3, 18, 5, 18, 8, -1, -1, 13, 8, 18, 8]], - "H": [22, [4, 21, 4, 0, -1, -1, 18, 21, 18, 0, -1, -1, 4, 11, 18, 11]], - "I": [8, [4, 21, 4, 0]], - "J": [16, [12, 21, 12, 5, 11, 2, 10, 1, 8, 0, 6, 0, 4, 1, 3, 2, 2, 5, 2, 7]], - "K": [21, [4, 21, 4, 0, -1, -1, 18, 21, 4, 7, -1, -1, 9, 12, 18, 0]], - "L": [17, [4, 21, 4, 0, -1, -1, 4, 0, 16, 0]], - "M": [24, [4, 21, 4, 0, -1, -1, 4, 21, 12, 0, -1, -1, 20, 21, 12, 0, -1, -1, 20, 21, 20, 0]], - "N": [22, [4, 21, 4, 0, -1, -1, 4, 21, 18, 0, -1, -1, 18, 21, 18, 0]], - "O": [22, [9, 21, 7, 20, 5, 18, 4, 16, 3, 13, 3, 8, 4, 5, 5, 3, 7, 1, 9, 0, 13, 0, 15, 1, 17, 3, 18, 5, 19, 8, 19, 13, 18, 16, 17, 18, 15, 20, 13, 21, 9, 21]], - "P": [21, [4, 21, 4, 0, -1, -1, 4, 21, 13, 21, 16, 20, 17, 19, 18, 17, 18, 14, 17, 12, 16, 11, 13, 10, 4, 10]], - "Q": [22, [9, 21, 7, 20, 5, 18, 4, 16, 3, 13, 3, 8, 4, 5, 5, 3, 7, 1, 9, 0, 13, 0, 15, 1, 17, 3, 18, 5, 19, 8, 19, 13, 18, 16, 17, 18, 15, 20, 13, 21, 9, 21, -1, -1, 12, 4, 18, -2]], - "R": [21, [4, 21, 4, 0, -1, -1, 4, 21, 13, 21, 16, 20, 17, 19, 18, 17, 18, 15, 17, 13, 16, 12, 13, 11, 4, 11, -1, -1, 11, 11, 18, 0]], - "S": [20, [17, 18, 15, 20, 12, 21, 8, 21, 5, 20, 3, 18, 3, 16, 4, 14, 5, 13, 7, 12, 13, 10, 15, 9, 16, 8, 17, 6, 17, 3, 15, 1, 12, 0, 8, 0, 5, 1, 3, 3]], - "T": [16, [8, 21, 8, 0, -1, -1, 1, 21, 15, 21]], - "U": [22, [4, 21, 4, 6, 5, 3, 7, 1, 10, 0, 12, 0, 15, 1, 17, 3, 18, 6, 18, 21]], - "V": [18, [1, 21, 9, 0, -1, -1, 17, 21, 9, 0]], - "W": [24, [2, 21, 7, 0, -1, -1, 12, 21, 7, 0, -1, -1, 12, 21, 17, 0, -1, -1, 22, 21, 17, 0]], - "X": [20, [3, 21, 17, 0, -1, -1, 17, 21, 3, 0]], - "Y": [18, [1, 21, 9, 11, 9, 0, -1, -1, 17, 21, 9, 11]], - "Z": [20, [17, 21, 3, 0, -1, -1, 3, 21, 17, 21, -1, -1, 3, 0, 17, 0]], - "[": [14, [4, 25, 4, -7, -1, -1, 5, 25, 5, -7, -1, -1, 4, 25, 11, 25, -1, -1, 4, -7, 11, -7]], - "\\": [14, [0, 21, 14, -3]], - "]": [14, [9, 25, 9, -7, -1, -1, 10, 25, 10, -7, -1, -1, 3, 25, 10, 25, -1, -1, 3, -7, 10, -7]], - "^": [16, [6, 15, 8, 18, 10, 15, -1, -1, 3, 12, 8, 17, 13, 12, -1, -1, 8, 17, 8, 0]], - "_": [16, [0, -2, 16, -2]], - "`": [10, [6, 21, 5, 20, 4, 18, 4, 16, 5, 15, 6, 16, 5, 17]], - "a": [19, [15, 14, 15, 0, -1, -1, 15, 11, 13, 13, 11, 14, 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3]], - "b": [19, [4, 21, 4, 0, -1, -1, 4, 11, 6, 13, 8, 14, 11, 14, 13, 13, 15, 11, 16, 8, 16, 6, 15, 3, 13, 1, 11, 0, 8, 0, 6, 1, 4, 3]], - "c": [18, [15, 11, 13, 13, 11, 14, 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3]], - "d": [19, [15, 21, 15, 0, -1, -1, 15, 11, 13, 13, 11, 14, 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3]], - "e": [18, [3, 8, 15, 8, 15, 10, 14, 12, 13, 13, 11, 14, 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3]], - "f": [12, [10, 21, 8, 21, 6, 20, 5, 17, 5, 0, -1, -1, 2, 14, 9, 14]], - "g": [19, [15, 14, 15, -2, 14, -5, 13, -6, 11, -7, 8, -7, 6, -6, -1, -1, 15, 11, 13, 13, 11, 14, 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3]], - "h": [19, [4, 21, 4, 0, -1, -1, 4, 10, 7, 13, 9, 14, 12, 14, 14, 13, 15, 10, 15, 0]], - "i": [8, [3, 21, 4, 20, 5, 21, 4, 22, 3, 21, -1, -1, 4, 14, 4, 0]], - "j": [10, [5, 21, 6, 20, 7, 21, 6, 22, 5, 21, -1, -1, 6, 14, 6, -3, 5, -6, 3, -7, 1, -7]], - "k": [17, [4, 21, 4, 0, -1, -1, 14, 14, 4, 4, -1, -1, 8, 8, 15, 0]], - "l": [8, [4, 21, 4, 0]], - "m": [30, [4, 14, 4, 0, -1, -1, 4, 10, 7, 13, 9, 14, 12, 14, 14, 13, 15, 10, 15, 0, -1, -1, 15, 10, 18, 13, 20, 14, 23, 14, 25, 13, 26, 10, 26, 0]], - "n": [19, [4, 14, 4, 0, -1, -1, 4, 10, 7, 13, 9, 14, 12, 14, 14, 13, 15, 10, 15, 0]], - "o": [19, [8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3, 16, 6, 16, 8, 15, 11, 13, 13, 11, 14, 8, 14]], - "p": [19, [4, 14, 4, -7, -1, -1, 4, 11, 6, 13, 8, 14, 11, 14, 13, 13, 15, 11, 16, 8, 16, 6, 15, 3, 13, 1, 11, 0, 8, 0, 6, 1, 4, 3]], - "q": [19, [15, 14, 15, -7, -1, -1, 15, 11, 13, 13, 11, 14, 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3]], - "r": [13, [4, 14, 4, 0, -1, -1, 4, 8, 5, 11, 7, 13, 9, 14, 12, 14]], - "s": [17, [14, 11, 13, 13, 10, 14, 7, 14, 4, 13, 3, 11, 4, 9, 6, 8, 11, 7, 13, 6, 14, 4, 14, 3, 13, 1, 10, 0, 7, 0, 4, 1, 3, 3]], - "t": [12, [5, 21, 5, 4, 6, 1, 8, 0, 10, 0, -1, -1, 2, 14, 9, 14]], - "u": [19, [4, 14, 4, 4, 5, 1, 7, 0, 10, 0, 12, 1, 15, 4, -1, -1, 15, 14, 15, 0]], - "v": [16, [2, 14, 8, 0, -1, -1, 14, 14, 8, 0]], - "w": [22, [3, 14, 7, 0, -1, -1, 11, 14, 7, 0, -1, -1, 11, 14, 15, 0, -1, -1, 19, 14, 15, 0]], - "x": [17, [3, 14, 14, 0, -1, -1, 14, 14, 3, 0]], - "y": [16, [2, 14, 8, 0, -1, -1, 14, 14, 8, 0, 6, -4, 4, -6, 2, -7, 1, -7]], - "z": [17, [14, 14, 3, 0, -1, -1, 3, 14, 14, 14, -1, -1, 3, 0, 14, 0]], - "{": [14, [9, 25, 7, 24, 6, 23, 5, 21, 5, 19, 6, 17, 7, 16, 8, 14, 8, 12, 6, 10, -1, -1, 7, 24, 6, 22, 6, 20, 7, 18, 8, 17, 9, 15, 9, 13, 8, 11, 4, 9, 8, 7, 9, 5, 9, 3, 8, 1, 7, 0, 6, -2, 6, -4, 7, -6, -1, -1, 6, 8, 8, 6, 8, 4, 7, 2, 6, 1, 5, -1, 5, -3, 6, -5, 7, -6, 9, -7]], - "|": [8, [4, 25, 4, -7]], - "}": [14, [5, 25, 7, 24, 8, 23, 9, 21, 9, 19, 8, 17, 7, 16, 6, 14, 6, 12, 8, 10, -1, -1, 7, 24, 8, 22, 8, 20, 7, 18, 6, 17, 5, 15, 5, 13, 6, 11, 10, 9, 6, 7, 5, 5, 5, 3, 6, 1, 7, 0, 8, -2, 8, -4, 7, -6, -1, -1, 8, 8, 6, 6, 6, 4, 7, 2, 8, 1, 9, -1, 9, -3, 8, -5, 7, -6, 5, -7]], - "~": [24, [3, 6, 3, 8, 4, 11, 6, 12, 8, 12, 10, 11, 14, 8, 16, 7, 18, 7, 20, 8, 21, 10, -1, -1, 3, 8, 4, 10, 6, 11, 8, 11, 10, 10, 14, 7, 16, 6, 18, 6, 20, 7, 21, 10, 21, 12]] +/** + * Returns a string representation of a mat3 + * + * @param {mat3} mat matrix to represent as a string + * @returns {String} string representation of the matrix + */ +mat3.str = function (a) { + return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + + a[6] + ', ' + a[7] + ', ' + a[8] + ')'; }; -module.exports = function textVertices(text, left, baseline, scale) { - scale = scale || 1; +/** + * Returns Frobenius norm of a mat3 + * + * @param {mat3} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ +mat3.frob = function (a) { + return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2))) +}; - var strokes = [], - i, len, j, len2, glyph, x, y, prev; +/** + * Adds two mat3's + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the first operand + * @param {mat3} b the second operand + * @returns {mat3} out + */ +mat3.add = function(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + out[6] = a[6] + b[6]; + out[7] = a[7] + b[7]; + out[8] = a[8] + b[8]; + return out; +}; - for (i = 0, len = text.length; i < len; i++) { - glyph = simplexFont[text[i]]; - if (!glyph) continue; - prev = null; +/** + * Subtracts matrix b from matrix a + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the first operand + * @param {mat3} b the second operand + * @returns {mat3} out + */ +mat3.subtract = function(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + out[4] = a[4] - b[4]; + out[5] = a[5] - b[5]; + out[6] = a[6] - b[6]; + out[7] = a[7] - b[7]; + out[8] = a[8] - b[8]; + return out; +}; - for (j = 0, len2 = glyph[1].length; j < len2; j += 2) { - if (glyph[1][j] === -1 && glyph[1][j + 1] === -1) { - prev = null; +/** + * Alias for {@link mat3.subtract} + * @function + */ +mat3.sub = mat3.subtract; - } else { - x = left + glyph[1][j] * scale; - y = baseline - glyph[1][j + 1] * scale; - if (prev) { - strokes.push(prev.x, prev.y, x, y); - } - prev = {x: x, y: y}; - } - } - left += glyph[0] * scale; - } +/** + * Multiply each element of the matrix by a scalar. + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to scale + * @param {Number} b amount to scale the matrix's elements by + * @returns {mat3} out + */ +mat3.multiplyScalar = function(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + out[4] = a[4] * b; + out[5] = a[5] * b; + out[6] = a[6] * b; + out[7] = a[7] * b; + out[8] = a[8] * b; + return out; +}; - return strokes; +/** + * Adds two mat3's after multiplying each element of the second operand by a scalar value. + * + * @param {mat3} out the receiving vector + * @param {mat3} a the first operand + * @param {mat3} b the second operand + * @param {Number} scale the amount to scale b's elements by before adding + * @returns {mat3} out + */ +mat3.multiplyScalarAndAdd = function(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + out[2] = a[2] + (b[2] * scale); + out[3] = a[3] + (b[3] * scale); + out[4] = a[4] + (b[4] * scale); + out[5] = a[5] + (b[5] * scale); + out[6] = a[6] + (b[6] * scale); + out[7] = a[7] + (b[7] * scale); + out[8] = a[8] + (b[8] * scale); + return out; }; -},{}],30:[function(require,module,exports){ -'use strict'; +/* + * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) + * + * @param {mat3} a The first matrix. + * @param {mat3} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ +mat3.exactEquals = function (a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && + a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && + a[6] === b[6] && a[7] === b[7] && a[8] === b[8]; +}; /** - * mapboxgl is a A WebGL JavaScript interactive maps library that can render - * [Mapbox vector tiles](https://www.mapbox.com/blog/vector-tiles/). + * Returns whether or not the matrices have approximately the same elements in the same position. * - * @module mapboxgl - * @summary WebGL JavaScript map library + * @param {mat3} a The first matrix. + * @param {mat3} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. */ +mat3.equals = function (a, b) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7], a8 = a[8]; + var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5], b6 = a[6], b7 = b[7], b8 = b[8]; + return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && + Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) && + Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) && + Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) && + Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) && + Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)) && + Math.abs(a6 - b6) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a6), Math.abs(b6)) && + Math.abs(a7 - b7) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a7), Math.abs(b7)) && + Math.abs(a8 - b8) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a8), Math.abs(b8))); +}; -// jshint -W079 -var mapboxgl = module.exports = {}; - -mapboxgl.Map = require('./ui/map'); -mapboxgl.Control = require('./ui/control/control'); -mapboxgl.Navigation = require('./ui/control/navigation'); -mapboxgl.Attribution = require('./ui/control/attribution'); -mapboxgl.Popup = require('./ui/popup'); -mapboxgl.GeoJSONSource = require('./source/geojson_source'); -mapboxgl.VideoSource = require('./source/video_source'); -mapboxgl.ImageSource = require('./source/image_source'); +module.exports = mat3; -mapboxgl.Style = require('./style/style'); +},{"./common.js":30}],34:[function(require,module,exports){ +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. -mapboxgl.LngLat = require('./geo/lng_lat'); -mapboxgl.LngLatBounds = require('./geo/lng_lat_bounds'); -mapboxgl.Point = require('point-geometry'); +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: -mapboxgl.Evented = require('./util/evented'); -mapboxgl.util = require('./util/util'); +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. -mapboxgl.supported = require('./util/browser').supported; +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. */ -var ajax = require('./util/ajax'); -mapboxgl.util.getJSON = ajax.getJSON; -mapboxgl.util.getArrayBuffer = ajax.getArrayBuffer; +var glMatrix = require("./common.js"); -var config = require('./util/config'); -mapboxgl.config = config; +/** + * @class 4x4 Matrix + * @name mat4 + */ +var mat4 = { + scalar: {}, + SIMD: {}, +}; -Object.defineProperty(mapboxgl, 'accessToken', { - get: function() { return config.ACCESS_TOKEN; }, - set: function(token) { config.ACCESS_TOKEN = token; } -}); - -},{"./geo/lng_lat":26,"./geo/lng_lat_bounds":27,"./source/geojson_source":44,"./source/image_source":46,"./source/video_source":53,"./style/style":60,"./ui/control/attribution":86,"./ui/control/control":87,"./ui/control/navigation":88,"./ui/map":98,"./ui/popup":99,"./util/ajax":101,"./util/browser":102,"./util/config":106,"./util/evented":107,"./util/util":113,"point-geometry":162}],31:[function(require,module,exports){ -'use strict'; - -var TilePyramid = require('../source/tile_pyramid'); -var pyramid = new TilePyramid({ tileSize: 512 }); -var util = require('../util/util'); -var EXTENT = require('../data/buffer').EXTENT; +/** + * Creates a new identity mat4 + * + * @returns {mat4} a new 4x4 matrix + */ +mat4.create = function() { + var out = new glMatrix.ARRAY_TYPE(16); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +}; -module.exports = drawBackground; +/** + * Creates a new mat4 initialized with values from an existing matrix + * + * @param {mat4} a matrix to clone + * @returns {mat4} a new 4x4 matrix + */ +mat4.clone = function(a) { + var out = new glMatrix.ARRAY_TYPE(16); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; +}; -function drawBackground(painter, source, layer) { - var gl = painter.gl; - var transform = painter.transform; - var color = util.premultiply(layer.paint['background-color'], layer.paint['background-opacity']); - var image = layer.paint['background-pattern']; - var opacity = layer.paint['background-opacity']; - var shader; +/** + * Copy the values from one mat4 to another + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; +}; - var imagePosA = image ? painter.spriteAtlas.getPosition(image.from, true) : null; - var imagePosB = image ? painter.spriteAtlas.getPosition(image.to, true) : null; +/** + * Create a new mat4 with the given values + * + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m02 Component in column 0, row 2 position (index 2) + * @param {Number} m03 Component in column 0, row 3 position (index 3) + * @param {Number} m10 Component in column 1, row 0 position (index 4) + * @param {Number} m11 Component in column 1, row 1 position (index 5) + * @param {Number} m12 Component in column 1, row 2 position (index 6) + * @param {Number} m13 Component in column 1, row 3 position (index 7) + * @param {Number} m20 Component in column 2, row 0 position (index 8) + * @param {Number} m21 Component in column 2, row 1 position (index 9) + * @param {Number} m22 Component in column 2, row 2 position (index 10) + * @param {Number} m23 Component in column 2, row 3 position (index 11) + * @param {Number} m30 Component in column 3, row 0 position (index 12) + * @param {Number} m31 Component in column 3, row 1 position (index 13) + * @param {Number} m32 Component in column 3, row 2 position (index 14) + * @param {Number} m33 Component in column 3, row 3 position (index 15) + * @returns {mat4} A new mat4 + */ +mat4.fromValues = function(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) { + var out = new glMatrix.ARRAY_TYPE(16); + out[0] = m00; + out[1] = m01; + out[2] = m02; + out[3] = m03; + out[4] = m10; + out[5] = m11; + out[6] = m12; + out[7] = m13; + out[8] = m20; + out[9] = m21; + out[10] = m22; + out[11] = m23; + out[12] = m30; + out[13] = m31; + out[14] = m32; + out[15] = m33; + return out; +}; - painter.setDepthSublayer(0); - if (imagePosA && imagePosB) { +/** + * Set the components of a mat4 to the given values + * + * @param {mat4} out the receiving matrix + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m02 Component in column 0, row 2 position (index 2) + * @param {Number} m03 Component in column 0, row 3 position (index 3) + * @param {Number} m10 Component in column 1, row 0 position (index 4) + * @param {Number} m11 Component in column 1, row 1 position (index 5) + * @param {Number} m12 Component in column 1, row 2 position (index 6) + * @param {Number} m13 Component in column 1, row 3 position (index 7) + * @param {Number} m20 Component in column 2, row 0 position (index 8) + * @param {Number} m21 Component in column 2, row 1 position (index 9) + * @param {Number} m22 Component in column 2, row 2 position (index 10) + * @param {Number} m23 Component in column 2, row 3 position (index 11) + * @param {Number} m30 Component in column 3, row 0 position (index 12) + * @param {Number} m31 Component in column 3, row 1 position (index 13) + * @param {Number} m32 Component in column 3, row 2 position (index 14) + * @param {Number} m33 Component in column 3, row 3 position (index 15) + * @returns {mat4} out + */ +mat4.set = function(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) { + out[0] = m00; + out[1] = m01; + out[2] = m02; + out[3] = m03; + out[4] = m10; + out[5] = m11; + out[6] = m12; + out[7] = m13; + out[8] = m20; + out[9] = m21; + out[10] = m22; + out[11] = m23; + out[12] = m30; + out[13] = m31; + out[14] = m32; + out[15] = m33; + return out; +}; - if (painter.isOpaquePass) return; - // Draw texture fill - shader = painter.patternShader; - gl.switchShader(shader); - gl.uniform1i(shader.u_image, 0); - gl.uniform2fv(shader.u_pattern_tl_a, imagePosA.tl); - gl.uniform2fv(shader.u_pattern_br_a, imagePosA.br); - gl.uniform2fv(shader.u_pattern_tl_b, imagePosB.tl); - gl.uniform2fv(shader.u_pattern_br_b, imagePosB.br); - gl.uniform1f(shader.u_opacity, opacity); +/** + * Set a mat4 to the identity matrix + * + * @param {mat4} out the receiving matrix + * @returns {mat4} out + */ +mat4.identity = function(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +}; - gl.uniform1f(shader.u_mix, image.t); +/** + * Transpose the values of a mat4 not using SIMD + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.scalar.transpose = function(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (out === a) { + var a01 = a[1], a02 = a[2], a03 = a[3], + a12 = a[6], a13 = a[7], + a23 = a[11]; - var factor = (EXTENT / transform.tileSize) / Math.pow(2, 0); + out[1] = a[4]; + out[2] = a[8]; + out[3] = a[12]; + out[4] = a01; + out[6] = a[9]; + out[7] = a[13]; + out[8] = a02; + out[9] = a12; + out[11] = a[14]; + out[12] = a03; + out[13] = a13; + out[14] = a23; + } else { + out[0] = a[0]; + out[1] = a[4]; + out[2] = a[8]; + out[3] = a[12]; + out[4] = a[1]; + out[5] = a[5]; + out[6] = a[9]; + out[7] = a[13]; + out[8] = a[2]; + out[9] = a[6]; + out[10] = a[10]; + out[11] = a[14]; + out[12] = a[3]; + out[13] = a[7]; + out[14] = a[11]; + out[15] = a[15]; + } - gl.uniform2fv(shader.u_patternscale_a, [ - 1 / (imagePosA.size[0] * factor * image.fromScale), - 1 / (imagePosA.size[1] * factor * image.fromScale) - ]); + return out; +}; - gl.uniform2fv(shader.u_patternscale_b, [ - 1 / (imagePosB.size[0] * factor * image.toScale), - 1 / (imagePosB.size[1] * factor * image.toScale) - ]); +/** + * Transpose the values of a mat4 using SIMD + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.SIMD.transpose = function(out, a) { + var a0, a1, a2, a3, + tmp01, tmp23, + out0, out1, out2, out3; + + a0 = SIMD.Float32x4.load(a, 0); + a1 = SIMD.Float32x4.load(a, 4); + a2 = SIMD.Float32x4.load(a, 8); + a3 = SIMD.Float32x4.load(a, 12); + + tmp01 = SIMD.Float32x4.shuffle(a0, a1, 0, 1, 4, 5); + tmp23 = SIMD.Float32x4.shuffle(a2, a3, 0, 1, 4, 5); + out0 = SIMD.Float32x4.shuffle(tmp01, tmp23, 0, 2, 4, 6); + out1 = SIMD.Float32x4.shuffle(tmp01, tmp23, 1, 3, 5, 7); + SIMD.Float32x4.store(out, 0, out0); + SIMD.Float32x4.store(out, 4, out1); + + tmp01 = SIMD.Float32x4.shuffle(a0, a1, 2, 3, 6, 7); + tmp23 = SIMD.Float32x4.shuffle(a2, a3, 2, 3, 6, 7); + out2 = SIMD.Float32x4.shuffle(tmp01, tmp23, 0, 2, 4, 6); + out3 = SIMD.Float32x4.shuffle(tmp01, tmp23, 1, 3, 5, 7); + SIMD.Float32x4.store(out, 8, out2); + SIMD.Float32x4.store(out, 12, out3); - painter.spriteAtlas.bind(gl, true); + return out; +}; - } else { - // Draw filling rectangle. - if (painter.isOpaquePass !== (color[3] === 1)) return; +/** + * Transpse a mat4 using SIMD if available and enabled + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.transpose = glMatrix.USE_SIMD ? mat4.SIMD.transpose : mat4.scalar.transpose; - shader = painter.fillShader; - gl.switchShader(shader); - gl.uniform4fv(shader.u_color, color); - } +/** + * Inverts a mat4 not using SIMD + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.scalar.invert = function(out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], - gl.disable(gl.STENCIL_TEST); + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32, - gl.bindBuffer(gl.ARRAY_BUFFER, painter.tileExtentBuffer); - gl.vertexAttribPointer(shader.a_pos, painter.tileExtentBuffer.itemSize, gl.SHORT, false, 0, 0); + // Calculate the determinant + det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; - // We need to draw the background in tiles in order to use calculatePosMatrix - // which applies the projection matrix (transform.projMatrix). Otherwise - // the depth and stencil buffers get into a bad state. - // This can be refactored into a single draw call once earcut lands and - // we don't have so much going on in the stencil buffer. - var coords = pyramid.coveringTiles(transform); - for (var c = 0; c < coords.length; c++) { - gl.setPosMatrix(painter.calculatePosMatrix(coords[c])); - gl.drawArrays(gl.TRIANGLE_STRIP, 0, painter.tileExtentBuffer.itemCount); + if (!det) { + return null; } + det = 1.0 / det; - gl.stencilMask(0x00); - gl.stencilFunc(gl.EQUAL, 0x80, 0x80); -} + out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; + out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; + out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; + out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; + out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; + out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; + out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; + out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; + out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; + out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; -},{"../data/buffer":17,"../source/tile_pyramid":51,"../util/util":113}],32:[function(require,module,exports){ -'use strict'; + return out; +}; -var browser = require('../util/browser'); -var util = require('../util/util'); +/** + * Inverts a mat4 using SIMD + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.SIMD.invert = function(out, a) { + var row0, row1, row2, row3, + tmp1, + minor0, minor1, minor2, minor3, + det, + a0 = SIMD.Float32x4.load(a, 0), + a1 = SIMD.Float32x4.load(a, 4), + a2 = SIMD.Float32x4.load(a, 8), + a3 = SIMD.Float32x4.load(a, 12); + + // Compute matrix adjugate + tmp1 = SIMD.Float32x4.shuffle(a0, a1, 0, 1, 4, 5); + row1 = SIMD.Float32x4.shuffle(a2, a3, 0, 1, 4, 5); + row0 = SIMD.Float32x4.shuffle(tmp1, row1, 0, 2, 4, 6); + row1 = SIMD.Float32x4.shuffle(row1, tmp1, 1, 3, 5, 7); + tmp1 = SIMD.Float32x4.shuffle(a0, a1, 2, 3, 6, 7); + row3 = SIMD.Float32x4.shuffle(a2, a3, 2, 3, 6, 7); + row2 = SIMD.Float32x4.shuffle(tmp1, row3, 0, 2, 4, 6); + row3 = SIMD.Float32x4.shuffle(row3, tmp1, 1, 3, 5, 7); + + tmp1 = SIMD.Float32x4.mul(row2, row3); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2); + minor0 = SIMD.Float32x4.mul(row1, tmp1); + minor1 = SIMD.Float32x4.mul(row0, tmp1); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1); + minor0 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row1, tmp1), minor0); + minor1 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row0, tmp1), minor1); + minor1 = SIMD.Float32x4.swizzle(minor1, 2, 3, 0, 1); + + tmp1 = SIMD.Float32x4.mul(row1, row2); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2); + minor0 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row3, tmp1), minor0); + minor3 = SIMD.Float32x4.mul(row0, tmp1); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1); + minor0 = SIMD.Float32x4.sub(minor0, SIMD.Float32x4.mul(row3, tmp1)); + minor3 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row0, tmp1), minor3); + minor3 = SIMD.Float32x4.swizzle(minor3, 2, 3, 0, 1); + + tmp1 = SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(row1, 2, 3, 0, 1), row3); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2); + row2 = SIMD.Float32x4.swizzle(row2, 2, 3, 0, 1); + minor0 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row2, tmp1), minor0); + minor2 = SIMD.Float32x4.mul(row0, tmp1); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1); + minor0 = SIMD.Float32x4.sub(minor0, SIMD.Float32x4.mul(row2, tmp1)); + minor2 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row0, tmp1), minor2); + minor2 = SIMD.Float32x4.swizzle(minor2, 2, 3, 0, 1); + + tmp1 = SIMD.Float32x4.mul(row0, row1); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2); + minor2 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row3, tmp1), minor2); + minor3 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row2, tmp1), minor3); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1); + minor2 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row3, tmp1), minor2); + minor3 = SIMD.Float32x4.sub(minor3, SIMD.Float32x4.mul(row2, tmp1)); + + tmp1 = SIMD.Float32x4.mul(row0, row3); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2); + minor1 = SIMD.Float32x4.sub(minor1, SIMD.Float32x4.mul(row2, tmp1)); + minor2 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row1, tmp1), minor2); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1); + minor1 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row2, tmp1), minor1); + minor2 = SIMD.Float32x4.sub(minor2, SIMD.Float32x4.mul(row1, tmp1)); + + tmp1 = SIMD.Float32x4.mul(row0, row2); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2); + minor1 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row3, tmp1), minor1); + minor3 = SIMD.Float32x4.sub(minor3, SIMD.Float32x4.mul(row1, tmp1)); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1); + minor1 = SIMD.Float32x4.sub(minor1, SIMD.Float32x4.mul(row3, tmp1)); + minor3 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row1, tmp1), minor3); + + // Compute matrix determinant + det = SIMD.Float32x4.mul(row0, minor0); + det = SIMD.Float32x4.add(SIMD.Float32x4.swizzle(det, 2, 3, 0, 1), det); + det = SIMD.Float32x4.add(SIMD.Float32x4.swizzle(det, 1, 0, 3, 2), det); + tmp1 = SIMD.Float32x4.reciprocalApproximation(det); + det = SIMD.Float32x4.sub( + SIMD.Float32x4.add(tmp1, tmp1), + SIMD.Float32x4.mul(det, SIMD.Float32x4.mul(tmp1, tmp1))); + det = SIMD.Float32x4.swizzle(det, 0, 0, 0, 0); + if (!det) { + return null; + } -module.exports = drawCircles; + // Compute matrix inverse + SIMD.Float32x4.store(out, 0, SIMD.Float32x4.mul(det, minor0)); + SIMD.Float32x4.store(out, 4, SIMD.Float32x4.mul(det, minor1)); + SIMD.Float32x4.store(out, 8, SIMD.Float32x4.mul(det, minor2)); + SIMD.Float32x4.store(out, 12, SIMD.Float32x4.mul(det, minor3)); + return out; +} -function drawCircles(painter, source, layer, coords) { - if (painter.isOpaquePass) return; +/** + * Inverts a mat4 using SIMD if available and enabled + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.invert = glMatrix.USE_SIMD ? mat4.SIMD.invert : mat4.scalar.invert; - var gl = painter.gl; - - var shader = painter.circleShader; - painter.gl.switchShader(shader); - - painter.setDepthSublayer(0); - painter.depthMask(false); - - // Allow circles to be drawn across boundaries, so that - // large circles are not clipped to tiles - gl.disable(gl.STENCIL_TEST); - - // antialiasing factor: this is a minimum blur distance that serves as - // a faux-antialiasing for the circle. since blur is a ratio of the circle's - // size and the intent is to keep the blur at roughly 1px, the two - // are inversely related. - var antialias = 1 / browser.devicePixelRatio / layer.paint['circle-radius']; - - var color = util.premultiply(layer.paint['circle-color'], layer.paint['circle-opacity']); - gl.uniform4fv(shader.u_color, color); - gl.uniform1f(shader.u_blur, Math.max(layer.paint['circle-blur'], antialias)); - gl.uniform1f(shader.u_size, layer.paint['circle-radius']); +/** + * Calculates the adjugate of a mat4 not using SIMD + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.scalar.adjoint = function(out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; - for (var i = 0; i < coords.length; i++) { - var coord = coords[i]; + out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22)); + out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22)); + out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12)); + out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12)); + out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22)); + out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22)); + out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12)); + out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12)); + out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21)); + out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21)); + out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11)); + out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11)); + out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21)); + out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21)); + out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11)); + out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11)); + return out; +}; - var tile = source.getTile(coord); - if (!tile.buffers) continue; - var elementGroups = tile.getElementGroups(layer, 'circle'); - if (!elementGroups) continue; +/** + * Calculates the adjugate of a mat4 using SIMD + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.SIMD.adjoint = function(out, a) { + var a0, a1, a2, a3; + var row0, row1, row2, row3; + var tmp1; + var minor0, minor1, minor2, minor3; + + var a0 = SIMD.Float32x4.load(a, 0); + var a1 = SIMD.Float32x4.load(a, 4); + var a2 = SIMD.Float32x4.load(a, 8); + var a3 = SIMD.Float32x4.load(a, 12); + + // Transpose the source matrix. Sort of. Not a true transpose operation + tmp1 = SIMD.Float32x4.shuffle(a0, a1, 0, 1, 4, 5); + row1 = SIMD.Float32x4.shuffle(a2, a3, 0, 1, 4, 5); + row0 = SIMD.Float32x4.shuffle(tmp1, row1, 0, 2, 4, 6); + row1 = SIMD.Float32x4.shuffle(row1, tmp1, 1, 3, 5, 7); + + tmp1 = SIMD.Float32x4.shuffle(a0, a1, 2, 3, 6, 7); + row3 = SIMD.Float32x4.shuffle(a2, a3, 2, 3, 6, 7); + row2 = SIMD.Float32x4.shuffle(tmp1, row3, 0, 2, 4, 6); + row3 = SIMD.Float32x4.shuffle(row3, tmp1, 1, 3, 5, 7); + + tmp1 = SIMD.Float32x4.mul(row2, row3); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2); + minor0 = SIMD.Float32x4.mul(row1, tmp1); + minor1 = SIMD.Float32x4.mul(row0, tmp1); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1); + minor0 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row1, tmp1), minor0); + minor1 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row0, tmp1), minor1); + minor1 = SIMD.Float32x4.swizzle(minor1, 2, 3, 0, 1); + + tmp1 = SIMD.Float32x4.mul(row1, row2); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2); + minor0 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row3, tmp1), minor0); + minor3 = SIMD.Float32x4.mul(row0, tmp1); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1); + minor0 = SIMD.Float32x4.sub(minor0, SIMD.Float32x4.mul(row3, tmp1)); + minor3 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row0, tmp1), minor3); + minor3 = SIMD.Float32x4.swizzle(minor3, 2, 3, 0, 1); + + tmp1 = SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(row1, 2, 3, 0, 1), row3); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2); + row2 = SIMD.Float32x4.swizzle(row2, 2, 3, 0, 1); + minor0 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row2, tmp1), minor0); + minor2 = SIMD.Float32x4.mul(row0, tmp1); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1); + minor0 = SIMD.Float32x4.sub(minor0, SIMD.Float32x4.mul(row2, tmp1)); + minor2 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row0, tmp1), minor2); + minor2 = SIMD.Float32x4.swizzle(minor2, 2, 3, 0, 1); + + tmp1 = SIMD.Float32x4.mul(row0, row1); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2); + minor2 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row3, tmp1), minor2); + minor3 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row2, tmp1), minor3); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1); + minor2 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row3, tmp1), minor2); + minor3 = SIMD.Float32x4.sub(minor3, SIMD.Float32x4.mul(row2, tmp1)); + + tmp1 = SIMD.Float32x4.mul(row0, row3); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2); + minor1 = SIMD.Float32x4.sub(minor1, SIMD.Float32x4.mul(row2, tmp1)); + minor2 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row1, tmp1), minor2); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1); + minor1 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row2, tmp1), minor1); + minor2 = SIMD.Float32x4.sub(minor2, SIMD.Float32x4.mul(row1, tmp1)); + + tmp1 = SIMD.Float32x4.mul(row0, row2); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2); + minor1 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row3, tmp1), minor1); + minor3 = SIMD.Float32x4.sub(minor3, SIMD.Float32x4.mul(row1, tmp1)); + tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1); + minor1 = SIMD.Float32x4.sub(minor1, SIMD.Float32x4.mul(row3, tmp1)); + minor3 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row1, tmp1), minor3); + + SIMD.Float32x4.store(out, 0, minor0); + SIMD.Float32x4.store(out, 4, minor1); + SIMD.Float32x4.store(out, 8, minor2); + SIMD.Float32x4.store(out, 12, minor3); + return out; +}; - var vertex = tile.buffers.circleVertex; - var elements = tile.buffers.circleElement; +/** + * Calculates the adjugate of a mat4 using SIMD if available and enabled + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ + mat4.adjoint = glMatrix.USE_SIMD ? mat4.SIMD.adjoint : mat4.scalar.adjoint; - gl.setPosMatrix(painter.translatePosMatrix( - painter.calculatePosMatrix(coord, source.maxzoom), - tile, - layer.paint['circle-translate'], - layer.paint['circle-translate-anchor'] - )); - gl.setExMatrix(painter.transform.exMatrix); +/** + * Calculates the determinant of a mat4 + * + * @param {mat4} a the source matrix + * @returns {Number} determinant of a + */ +mat4.determinant = function (a) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], - for (var k = 0; k < elementGroups.groups.length; k++) { - var group = elementGroups.groups[k]; - var offset = group.vertexStartIndex * vertex.itemSize; + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32; - vertex.bind(gl); - vertex.setAttribPointers(gl, shader, offset); + // Calculate the determinant + return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; +}; - elements.bind(gl); +/** + * Multiplies two mat4's explicitly using SIMD + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the first operand, must be a Float32Array + * @param {mat4} b the second operand, must be a Float32Array + * @returns {mat4} out + */ +mat4.SIMD.multiply = function (out, a, b) { + var a0 = SIMD.Float32x4.load(a, 0); + var a1 = SIMD.Float32x4.load(a, 4); + var a2 = SIMD.Float32x4.load(a, 8); + var a3 = SIMD.Float32x4.load(a, 12); + + var b0 = SIMD.Float32x4.load(b, 0); + var out0 = SIMD.Float32x4.add( + SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b0, 0, 0, 0, 0), a0), + SIMD.Float32x4.add( + SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b0, 1, 1, 1, 1), a1), + SIMD.Float32x4.add( + SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b0, 2, 2, 2, 2), a2), + SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b0, 3, 3, 3, 3), a3)))); + SIMD.Float32x4.store(out, 0, out0); + + var b1 = SIMD.Float32x4.load(b, 4); + var out1 = SIMD.Float32x4.add( + SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b1, 0, 0, 0, 0), a0), + SIMD.Float32x4.add( + SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b1, 1, 1, 1, 1), a1), + SIMD.Float32x4.add( + SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b1, 2, 2, 2, 2), a2), + SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b1, 3, 3, 3, 3), a3)))); + SIMD.Float32x4.store(out, 4, out1); + + var b2 = SIMD.Float32x4.load(b, 8); + var out2 = SIMD.Float32x4.add( + SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b2, 0, 0, 0, 0), a0), + SIMD.Float32x4.add( + SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b2, 1, 1, 1, 1), a1), + SIMD.Float32x4.add( + SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b2, 2, 2, 2, 2), a2), + SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b2, 3, 3, 3, 3), a3)))); + SIMD.Float32x4.store(out, 8, out2); + + var b3 = SIMD.Float32x4.load(b, 12); + var out3 = SIMD.Float32x4.add( + SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b3, 0, 0, 0, 0), a0), + SIMD.Float32x4.add( + SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b3, 1, 1, 1, 1), a1), + SIMD.Float32x4.add( + SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b3, 2, 2, 2, 2), a2), + SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b3, 3, 3, 3, 3), a3)))); + SIMD.Float32x4.store(out, 12, out3); - var count = group.elementLength * 3; - var elementOffset = group.elementStartIndex * elements.itemSize; - gl.drawElements(gl.TRIANGLES, count, gl.UNSIGNED_SHORT, elementOffset); - } - } -} + return out; +}; -},{"../util/browser":102,"../util/util":113}],33:[function(require,module,exports){ -'use strict'; +/** + * Multiplies two mat4's explicitly not using SIMD + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the first operand + * @param {mat4} b the second operand + * @returns {mat4} out + */ +mat4.scalar.multiply = function (out, a, b) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; -module.exports = drawCollisionDebug; + // Cache only the current line of the second matrix + var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; -function drawCollisionDebug(painter, source, layer, coords) { - var gl = painter.gl; - var shader = painter.collisionBoxShader; - gl.enable(gl.STENCIL_TEST); - gl.switchShader(shader); + b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; + out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - for (var i = 0; i < coords.length; i++) { - var coord = coords[i]; - var tile = source.getTile(coord); - var elementGroups = tile.getElementGroups(layer, 'collisionBox'); + b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; + out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - if (!elementGroups) continue; - if (!tile.buffers) continue; - if (elementGroups.groups[0].vertexLength === 0) continue; + b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; + out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + return out; +}; - var buffer = tile.buffers.collisionBoxVertex; - buffer.bind(gl); - buffer.setAttribPointers(gl, shader, 0); +/** + * Multiplies two mat4's using SIMD if available and enabled + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the first operand + * @param {mat4} b the second operand + * @returns {mat4} out + */ +mat4.multiply = glMatrix.USE_SIMD ? mat4.SIMD.multiply : mat4.scalar.multiply; - var posMatrix = painter.calculatePosMatrix(coord, source.maxzoom); - gl.setPosMatrix(posMatrix); +/** + * Alias for {@link mat4.multiply} + * @function + */ +mat4.mul = mat4.multiply; - painter.enableTileClippingMask(coord); +/** + * Translate a mat4 by the given vector not using SIMD + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to translate + * @param {vec3} v vector to translate by + * @returns {mat4} out + */ +mat4.scalar.translate = function (out, a, v) { + var x = v[0], y = v[1], z = v[2], + a00, a01, a02, a03, + a10, a11, a12, a13, + a20, a21, a22, a23; - gl.lineWidth(1); - gl.uniform1f(shader.u_scale, Math.pow(2, painter.transform.zoom - tile.coord.z)); - gl.uniform1f(shader.u_zoom, painter.transform.zoom * 10); - gl.uniform1f(shader.u_maxzoom, (tile.coord.z + 1) * 10); + if (a === out) { + out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; + out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; + out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; + out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; + } else { + a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; + a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; + a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; - gl.drawArrays( - gl.LINES, - elementGroups.groups[0].vertexStartIndex, - elementGroups.groups[0].vertexLength - ); + out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03; + out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13; + out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23; + out[12] = a00 * x + a10 * y + a20 * z + a[12]; + out[13] = a01 * x + a11 * y + a21 * z + a[13]; + out[14] = a02 * x + a12 * y + a22 * z + a[14]; + out[15] = a03 * x + a13 * y + a23 * z + a[15]; } -} - -},{}],34:[function(require,module,exports){ -'use strict'; - -var textVertices = require('../lib/debugtext'); -var browser = require('../util/browser'); -var mat4 = require('gl-matrix').mat4; -var EXTENT = require('../data/buffer').EXTENT; -module.exports = drawDebug; + return out; +}; -function drawDebug(painter, source, coords) { - if (painter.isOpaquePass) return; - if (!painter.options.debug) return; +/** + * Translates a mat4 by the given vector using SIMD + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to translate + * @param {vec3} v vector to translate by + * @returns {mat4} out + */ +mat4.SIMD.translate = function (out, a, v) { + var a0 = SIMD.Float32x4.load(a, 0), + a1 = SIMD.Float32x4.load(a, 4), + a2 = SIMD.Float32x4.load(a, 8), + a3 = SIMD.Float32x4.load(a, 12), + vec = SIMD.Float32x4(v[0], v[1], v[2] , 0); - for (var i = 0; i < coords.length; i++) { - drawDebugTile(painter, source, coords[i]); + if (a !== out) { + out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; + out[4] = a[4]; out[5] = a[5]; out[6] = a[6]; out[7] = a[7]; + out[8] = a[8]; out[9] = a[9]; out[10] = a[10]; out[11] = a[11]; } -} - -function drawDebugTile(painter, source, coord) { - var gl = painter.gl; - - gl.disable(gl.STENCIL_TEST); - gl.lineWidth(1 * browser.devicePixelRatio); - var posMatrix = painter.calculatePosMatrix(coord, source.maxzoom); - var shader = painter.debugShader; - gl.switchShader(shader, posMatrix); + a0 = SIMD.Float32x4.mul(a0, SIMD.Float32x4.swizzle(vec, 0, 0, 0, 0)); + a1 = SIMD.Float32x4.mul(a1, SIMD.Float32x4.swizzle(vec, 1, 1, 1, 1)); + a2 = SIMD.Float32x4.mul(a2, SIMD.Float32x4.swizzle(vec, 2, 2, 2, 2)); - // draw bounding rectangle - gl.bindBuffer(gl.ARRAY_BUFFER, painter.debugBuffer); - gl.vertexAttribPointer(shader.a_pos, painter.debugBuffer.itemSize, gl.SHORT, false, 0, 0); - gl.uniform4f(shader.u_color, 1, 0, 0, 1); - gl.drawArrays(gl.LINE_STRIP, 0, painter.debugBuffer.itemCount); + var t0 = SIMD.Float32x4.add(a0, SIMD.Float32x4.add(a1, SIMD.Float32x4.add(a2, a3))); + SIMD.Float32x4.store(out, 12, t0); - var vertices = textVertices(coord.toString(), 50, 200, 5); - gl.bindBuffer(gl.ARRAY_BUFFER, painter.debugTextBuffer); - gl.bufferData(gl.ARRAY_BUFFER, new Int16Array(vertices), gl.STREAM_DRAW); - gl.vertexAttribPointer(shader.a_pos, painter.debugTextBuffer.itemSize, gl.SHORT, false, 0, 0); - gl.uniform4f(shader.u_color, 1, 1, 1, 1); - - // Draw the halo with multiple 1px lines instead of one wider line because - // the gl spec doesn't guarantee support for lines with width > 1. - var tileSize = source.getTile(coord).tileSize; - var onePixel = EXTENT / (Math.pow(2, painter.transform.zoom - coord.z) * tileSize); - var translations = [[-1, -1], [-1, 1], [1, -1], [1, 1]]; - for (var i = 0; i < translations.length; i++) { - var translation = translations[i]; - gl.setPosMatrix(mat4.translate([], posMatrix, [onePixel * translation[0], onePixel * translation[1], 0])); - gl.drawArrays(gl.LINES, 0, vertices.length / painter.debugTextBuffer.itemSize); - } + return out; +}; - gl.uniform4f(shader.u_color, 0, 0, 0, 1); - gl.setPosMatrix(posMatrix); - gl.drawArrays(gl.LINES, 0, vertices.length / painter.debugTextBuffer.itemSize); -} +/** + * Translates a mat4 by the given vector using SIMD if available and enabled + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to translate + * @param {vec3} v vector to translate by + * @returns {mat4} out + */ +mat4.translate = glMatrix.USE_SIMD ? mat4.SIMD.translate : mat4.scalar.translate; -},{"../data/buffer":17,"../lib/debugtext":29,"../util/browser":102,"gl-matrix":123}],35:[function(require,module,exports){ -'use strict'; +/** + * Scales the mat4 by the dimensions in the given vec3 not using vectorization + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to scale + * @param {vec3} v the vec3 to scale the matrix by + * @returns {mat4} out + **/ +mat4.scalar.scale = function(out, a, v) { + var x = v[0], y = v[1], z = v[2]; -var browser = require('../util/browser'); -var util = require('../util/util'); + out[0] = a[0] * x; + out[1] = a[1] * x; + out[2] = a[2] * x; + out[3] = a[3] * x; + out[4] = a[4] * y; + out[5] = a[5] * y; + out[6] = a[6] * y; + out[7] = a[7] * y; + out[8] = a[8] * z; + out[9] = a[9] * z; + out[10] = a[10] * z; + out[11] = a[11] * z; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; +}; -module.exports = draw; +/** + * Scales the mat4 by the dimensions in the given vec3 using vectorization + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to scale + * @param {vec3} v the vec3 to scale the matrix by + * @returns {mat4} out + **/ +mat4.SIMD.scale = function(out, a, v) { + var a0, a1, a2; + var vec = SIMD.Float32x4(v[0], v[1], v[2], 0); -function draw(painter, source, layer, coords) { - var gl = painter.gl; - gl.enable(gl.STENCIL_TEST); + a0 = SIMD.Float32x4.load(a, 0); + SIMD.Float32x4.store( + out, 0, SIMD.Float32x4.mul(a0, SIMD.Float32x4.swizzle(vec, 0, 0, 0, 0))); - var color = util.premultiply(layer.paint['fill-color'], layer.paint['fill-opacity']); - var image = layer.paint['fill-pattern']; - var strokeColor = util.premultiply(layer.paint['fill-outline-color'], layer.paint['fill-opacity']); + a1 = SIMD.Float32x4.load(a, 4); + SIMD.Float32x4.store( + out, 4, SIMD.Float32x4.mul(a1, SIMD.Float32x4.swizzle(vec, 1, 1, 1, 1))); - // Draw fill - if (image ? !painter.isOpaquePass : painter.isOpaquePass === (color[3] === 1)) { - // Once we switch to earcut drawing we can pull most of the WebGL setup - // outside of this coords loop. - for (var i = 0; i < coords.length; i++) { - drawFill(painter, source, layer, coords[i]); - } - } + a2 = SIMD.Float32x4.load(a, 8); + SIMD.Float32x4.store( + out, 8, SIMD.Float32x4.mul(a2, SIMD.Float32x4.swizzle(vec, 2, 2, 2, 2))); - // Draw stroke - if (!painter.isOpaquePass && layer.paint['fill-antialias'] && !(layer.paint['fill-pattern'] && !strokeColor)) { - gl.switchShader(painter.outlineShader); - gl.lineWidth(2 * browser.devicePixelRatio * 10); + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; +}; - if (strokeColor) { - // If we defined a different color for the fill outline, we are - // going to ignore the bits in 0x07 and just care about the global - // clipping mask. - painter.setDepthSublayer(2); - - } else { - // Otherwise, we only want to drawFill the antialiased parts that are - // *outside* the current shape. This is important in case the fill - // or stroke color is translucent. If we wouldn't clip to outside - // the current shape, some pixels from the outline stroke overlapped - // the (non-antialiased) fill. - painter.setDepthSublayer(0); - } - - gl.uniform2f(painter.outlineShader.u_world, gl.drawingBufferWidth, gl.drawingBufferHeight); - gl.uniform4fv(painter.outlineShader.u_color, strokeColor ? strokeColor : color); - - for (var j = 0; j < coords.length; j++) { - drawStroke(painter, source, layer, coords[j]); - } - } -} - -function drawFill(painter, source, layer, coord) { - var tile = source.getTile(coord); - if (!tile.buffers) return; - var elementGroups = tile.getElementGroups(layer, 'fill'); - if (!elementGroups) return; - - var gl = painter.gl; - - var color = util.premultiply(layer.paint['fill-color'], layer.paint['fill-opacity']); - var image = layer.paint['fill-pattern']; - var opacity = layer.paint['fill-opacity']; - - var posMatrix = painter.calculatePosMatrix(coord, source.maxzoom); - var translatedPosMatrix = painter.translatePosMatrix(posMatrix, tile, layer.paint['fill-translate'], layer.paint['fill-translate-anchor']); - - // Draw the stencil mask. - painter.setDepthSublayer(1); - - // We're only drawFilling to the first seven bits (== support a maximum of - // 8 overlapping polygons in one place before we get rendering errors). - gl.stencilMask(0x07); - gl.clear(gl.STENCIL_BUFFER_BIT); +/** + * Scales the mat4 by the dimensions in the given vec3 using SIMD if available and enabled + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to scale + * @param {vec3} v the vec3 to scale the matrix by + * @returns {mat4} out + */ +mat4.scale = glMatrix.USE_SIMD ? mat4.SIMD.scale : mat4.scalar.scale; - // Draw front facing triangles. Wherever the 0x80 bit is 1, we are - // increasing the lower 7 bits by one if the triangle is a front-facing - // triangle. This means that all visible polygons should be in CCW - // orientation, while all holes (see below) are in CW orientation. - painter.enableTileClippingMask(coord); +/** + * Rotates a mat4 by the given angle around the given axis + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @param {vec3} axis the axis to rotate around + * @returns {mat4} out + */ +mat4.rotate = function (out, a, rad, axis) { + var x = axis[0], y = axis[1], z = axis[2], + len = Math.sqrt(x * x + y * y + z * z), + s, c, t, + a00, a01, a02, a03, + a10, a11, a12, a13, + a20, a21, a22, a23, + b00, b01, b02, + b10, b11, b12, + b20, b21, b22; - // When we do a nonzero fill, we count the number of times a pixel is - // covered by a counterclockwise polygon, and subtract the number of - // times it is "uncovered" by a clockwise polygon. - gl.stencilOpSeparate(gl.FRONT, gl.KEEP, gl.KEEP, gl.INCR_WRAP); - gl.stencilOpSeparate(gl.BACK, gl.KEEP, gl.KEEP, gl.DECR_WRAP); + if (Math.abs(len) < glMatrix.EPSILON) { return null; } - // When drawFilling a shape, we first drawFill all shapes to the stencil buffer - // and incrementing all areas where polygons are - gl.colorMask(false, false, false, false); - painter.depthMask(false); + len = 1 / len; + x *= len; + y *= len; + z *= len; - // Draw the actual triangle fan into the stencil buffer. - gl.switchShader(painter.fillShader, translatedPosMatrix); + s = Math.sin(rad); + c = Math.cos(rad); + t = 1 - c; - // Draw all buffers - var vertex = tile.buffers.fillVertex; - vertex.bind(gl); + a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; + a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; + a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; - var elements = tile.buffers.fillElement; - elements.bind(gl); + // Construct the elements of the rotation matrix + b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s; + b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s; + b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c; - for (var i = 0; i < elementGroups.groups.length; i++) { - var group = elementGroups.groups[i]; - var offset = group.vertexStartIndex * vertex.itemSize; - vertex.setAttribPointers(gl, painter.fillShader, offset); + // Perform rotation-specific matrix multiplication + out[0] = a00 * b00 + a10 * b01 + a20 * b02; + out[1] = a01 * b00 + a11 * b01 + a21 * b02; + out[2] = a02 * b00 + a12 * b01 + a22 * b02; + out[3] = a03 * b00 + a13 * b01 + a23 * b02; + out[4] = a00 * b10 + a10 * b11 + a20 * b12; + out[5] = a01 * b10 + a11 * b11 + a21 * b12; + out[6] = a02 * b10 + a12 * b11 + a22 * b12; + out[7] = a03 * b10 + a13 * b11 + a23 * b12; + out[8] = a00 * b20 + a10 * b21 + a20 * b22; + out[9] = a01 * b20 + a11 * b21 + a21 * b22; + out[10] = a02 * b20 + a12 * b21 + a22 * b22; + out[11] = a03 * b20 + a13 * b21 + a23 * b22; - var count = group.elementLength * 3; - var elementOffset = group.elementStartIndex * elements.itemSize; - gl.drawElements(gl.TRIANGLES, count, gl.UNSIGNED_SHORT, elementOffset); + if (a !== out) { // If the source and destination differ, copy the unchanged last row + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; } + return out; +}; - // Now that we have the stencil mask in the stencil buffer, we can start - // writing to the color buffer. - gl.colorMask(true, true, true, true); - painter.depthMask(true); - - // From now on, we don't want to update the stencil buffer anymore. - gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); - gl.stencilMask(0x0); - var shader; - - if (image) { - // Draw texture fill - var imagePosA = painter.spriteAtlas.getPosition(image.from, true); - var imagePosB = painter.spriteAtlas.getPosition(image.to, true); - if (!imagePosA || !imagePosB) return; - - shader = painter.patternShader; - gl.switchShader(shader, posMatrix); - gl.uniform1i(shader.u_image, 0); - gl.uniform2fv(shader.u_pattern_tl_a, imagePosA.tl); - gl.uniform2fv(shader.u_pattern_br_a, imagePosA.br); - gl.uniform2fv(shader.u_pattern_tl_b, imagePosB.tl); - gl.uniform2fv(shader.u_pattern_br_b, imagePosB.br); - gl.uniform1f(shader.u_opacity, opacity); - gl.uniform1f(shader.u_mix, image.t); - - var imageSizeScaledA = [ - (imagePosA.size[0] * image.fromScale), - (imagePosA.size[1] * image.fromScale) - ]; - var imageSizeScaledB = [ - (imagePosB.size[0] * image.toScale), - (imagePosB.size[1] * image.toScale) - ]; - - gl.uniform2fv(shader.u_patternscale_a, [ - 1 / tile.pixelsToTileUnits(imageSizeScaledA[0], painter.transform.tileZoom), - 1 / tile.pixelsToTileUnits(imageSizeScaledA[1], painter.transform.tileZoom) - ]); - - gl.uniform2fv(shader.u_patternscale_b, [ - 1 / tile.pixelsToTileUnits(imageSizeScaledB[0], painter.transform.tileZoom), - 1 / tile.pixelsToTileUnits(imageSizeScaledB[1], painter.transform.tileZoom) - ]); - - var tileSizeAtNearestZoom = tile.tileSize * Math.pow(2, painter.transform.tileZoom - tile.coord.z); - - // shift images to match at tile boundaries - var offsetAx = ((tileSizeAtNearestZoom / imageSizeScaledA[0]) % 1) * (tile.coord.x + coord.w * Math.pow(2, tile.coord.z)); - var offsetAy = ((tileSizeAtNearestZoom / imageSizeScaledA[1]) % 1) * tile.coord.y; - - var offsetBx = ((tileSizeAtNearestZoom / imageSizeScaledB[0]) % 1) * (tile.coord.x + coord.w * Math.pow(2, tile.coord.z)); - var offsetBy = ((tileSizeAtNearestZoom / imageSizeScaledB[1]) % 1) * tile.coord.y; - - gl.uniform2fv(shader.u_offset_a, [offsetAx, offsetAy]); - gl.uniform2fv(shader.u_offset_b, [offsetBx, offsetBy]); - - painter.spriteAtlas.bind(gl, true); +/** + * Rotates a matrix by the given angle around the X axis not using SIMD + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +mat4.scalar.rotateX = function (out, a, rad) { + var s = Math.sin(rad), + c = Math.cos(rad), + a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7], + a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11]; - } else { - // Draw filling rectangle. - shader = painter.fillShader; - gl.switchShader(shader, posMatrix); - gl.uniform4fv(shader.u_color, color); + if (a !== out) { // If the source and destination differ, copy the unchanged rows + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; } - // Only draw regions that we marked - gl.stencilFunc(gl.NOTEQUAL, 0x0, 0x07); - gl.bindBuffer(gl.ARRAY_BUFFER, painter.tileExtentBuffer); - gl.vertexAttribPointer(shader.a_pos, painter.tileExtentBuffer.itemSize, gl.SHORT, false, 0, 0); - gl.drawArrays(gl.TRIANGLE_STRIP, 0, painter.tileExtentBuffer.itemCount); - - gl.stencilMask(0x00); -} - -function drawStroke(painter, source, layer, coord) { - var tile = source.getTile(coord); - if (!tile.buffers) return; - if (!tile.elementGroups[layer.ref || layer.id]) return; - - var gl = painter.gl; - var elementGroups = tile.elementGroups[layer.ref || layer.id].fill; - - gl.setPosMatrix(painter.translatePosMatrix( - painter.calculatePosMatrix(coord, source.maxzoom), - tile, - layer.paint['fill-translate'], - layer.paint['fill-translate-anchor'] - )); - - // Draw all buffers - var vertex = tile.buffers.fillVertex; - var elements = tile.buffers.fillSecondElement; - vertex.bind(gl); - elements.bind(gl); - - painter.enableTileClippingMask(coord); + // Perform axis-specific matrix multiplication + out[4] = a10 * c + a20 * s; + out[5] = a11 * c + a21 * s; + out[6] = a12 * c + a22 * s; + out[7] = a13 * c + a23 * s; + out[8] = a20 * c - a10 * s; + out[9] = a21 * c - a11 * s; + out[10] = a22 * c - a12 * s; + out[11] = a23 * c - a13 * s; + return out; +}; - for (var k = 0; k < elementGroups.groups.length; k++) { - var group = elementGroups.groups[k]; - var offset = group.vertexStartIndex * vertex.itemSize; - vertex.setAttribPointers(gl, painter.outlineShader, offset); +/** + * Rotates a matrix by the given angle around the X axis using SIMD + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +mat4.SIMD.rotateX = function (out, a, rad) { + var s = SIMD.Float32x4.splat(Math.sin(rad)), + c = SIMD.Float32x4.splat(Math.cos(rad)); - var count = group.secondElementLength * 2; - var elementOffset = group.secondElementStartIndex * elements.itemSize; - gl.drawElements(gl.LINES, count, gl.UNSIGNED_SHORT, elementOffset); + if (a !== out) { // If the source and destination differ, copy the unchanged rows + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; } -} - -},{"../util/browser":102,"../util/util":113}],36:[function(require,module,exports){ -'use strict'; -var browser = require('../util/browser'); -var mat2 = require('gl-matrix').mat2; -var util = require('../util/util'); + // Perform axis-specific matrix multiplication + var a_1 = SIMD.Float32x4.load(a, 4); + var a_2 = SIMD.Float32x4.load(a, 8); + SIMD.Float32x4.store(out, 4, + SIMD.Float32x4.add(SIMD.Float32x4.mul(a_1, c), SIMD.Float32x4.mul(a_2, s))); + SIMD.Float32x4.store(out, 8, + SIMD.Float32x4.sub(SIMD.Float32x4.mul(a_2, c), SIMD.Float32x4.mul(a_1, s))); + return out; +}; /** - * Draw a line. Under the hood this will read elements from - * a tile, dash textures from a lineAtlas, and style properties from a layer. - * @param {Object} painter - * @param {Object} layer - * @param {Object} posMatrix - * @param {Tile} tile - * @returns {undefined} draws with the painter - * @private + * Rotates a matrix by the given angle around the X axis using SIMD if availabe and enabled + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out */ -module.exports = function drawLine(painter, source, layer, coords) { - if (painter.isOpaquePass) return; - painter.setDepthSublayer(0); - painter.depthMask(false); - - var hasData = coords.some(function(coord) { - return source.getTile(coord).getElementGroups(layer, 'line'); - }); - if (!hasData) return; - - var gl = painter.gl; - gl.enable(gl.STENCIL_TEST); - - // don't draw zero-width lines - if (layer.paint['line-width'] <= 0) return; - - // the distance over which the line edge fades out. - // Retina devices need a smaller distance to avoid aliasing. - var antialiasing = 1 / browser.devicePixelRatio; - - var blur = layer.paint['line-blur'] + antialiasing; - var edgeWidth = layer.paint['line-width'] / 2; - var inset = -1; - var offset = 0; - var shift = 0; +mat4.rotateX = glMatrix.USE_SIMD ? mat4.SIMD.rotateX : mat4.scalar.rotateX; - if (layer.paint['line-gap-width'] > 0) { - inset = layer.paint['line-gap-width'] / 2 + antialiasing * 0.5; - edgeWidth = layer.paint['line-width']; +/** + * Rotates a matrix by the given angle around the Y axis not using SIMD + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +mat4.scalar.rotateY = function (out, a, rad) { + var s = Math.sin(rad), + c = Math.cos(rad), + a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3], + a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11]; - // shift outer lines half a pixel towards the middle to eliminate the crack - offset = inset - antialiasing / 2; + if (a !== out) { // If the source and destination differ, copy the unchanged rows + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; } - var outset = offset + edgeWidth + antialiasing / 2 + shift; - var color = util.premultiply(layer.paint['line-color'], layer.paint['line-opacity']); + // Perform axis-specific matrix multiplication + out[0] = a00 * c - a20 * s; + out[1] = a01 * c - a21 * s; + out[2] = a02 * c - a22 * s; + out[3] = a03 * c - a23 * s; + out[8] = a00 * s + a20 * c; + out[9] = a01 * s + a21 * c; + out[10] = a02 * s + a22 * c; + out[11] = a03 * s + a23 * c; + return out; +}; - var tr = painter.transform; +/** + * Rotates a matrix by the given angle around the Y axis using SIMD + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +mat4.SIMD.rotateY = function (out, a, rad) { + var s = SIMD.Float32x4.splat(Math.sin(rad)), + c = SIMD.Float32x4.splat(Math.cos(rad)); - var antialiasingMatrix = mat2.create(); - mat2.scale(antialiasingMatrix, antialiasingMatrix, [1, Math.cos(tr._pitch)]); - mat2.rotate(antialiasingMatrix, antialiasingMatrix, painter.transform.angle); + if (a !== out) { // If the source and destination differ, copy the unchanged rows + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } - // calculate how much longer the real world distance is at the top of the screen - // than at the middle of the screen. - var topedgelength = Math.sqrt(tr.height * tr.height / 4 * (1 + tr.altitude * tr.altitude)); - var x = tr.height / 2 * Math.tan(tr._pitch); - var extra = (topedgelength + x) / topedgelength - 1; + // Perform axis-specific matrix multiplication + var a_0 = SIMD.Float32x4.load(a, 0); + var a_2 = SIMD.Float32x4.load(a, 8); + SIMD.Float32x4.store(out, 0, + SIMD.Float32x4.sub(SIMD.Float32x4.mul(a_0, c), SIMD.Float32x4.mul(a_2, s))); + SIMD.Float32x4.store(out, 8, + SIMD.Float32x4.add(SIMD.Float32x4.mul(a_0, s), SIMD.Float32x4.mul(a_2, c))); + return out; +}; - var dasharray = layer.paint['line-dasharray']; - var image = layer.paint['line-pattern']; - var shader, posA, posB, imagePosA, imagePosB; +/** + * Rotates a matrix by the given angle around the Y axis if SIMD available and enabled + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ + mat4.rotateY = glMatrix.USE_SIMD ? mat4.SIMD.rotateY : mat4.scalar.rotateY; - if (dasharray) { - shader = painter.linesdfpatternShader; - gl.switchShader(shader); - - gl.uniform2fv(shader.u_linewidth, [ outset, inset ]); - gl.uniform1f(shader.u_blur, blur); - gl.uniform4fv(shader.u_color, color); - - posA = painter.lineAtlas.getDash(dasharray.from, layer.layout['line-cap'] === 'round'); - posB = painter.lineAtlas.getDash(dasharray.to, layer.layout['line-cap'] === 'round'); - painter.lineAtlas.bind(gl); - - gl.uniform1f(shader.u_tex_y_a, posA.y); - gl.uniform1f(shader.u_tex_y_b, posB.y); - gl.uniform1i(shader.u_image, 0); - gl.uniform1f(shader.u_mix, dasharray.t); - - gl.uniform1f(shader.u_extra, extra); - gl.uniform1f(shader.u_offset, -layer.paint['line-offset']); - gl.uniformMatrix2fv(shader.u_antialiasingmatrix, false, antialiasingMatrix); - - } else if (image) { - imagePosA = painter.spriteAtlas.getPosition(image.from, true); - imagePosB = painter.spriteAtlas.getPosition(image.to, true); - if (!imagePosA || !imagePosB) return; - - painter.spriteAtlas.bind(gl, true); - - shader = painter.linepatternShader; - gl.switchShader(shader); - - gl.uniform2fv(shader.u_linewidth, [ outset, inset ]); - gl.uniform1f(shader.u_blur, blur); - gl.uniform2fv(shader.u_pattern_tl_a, imagePosA.tl); - gl.uniform2fv(shader.u_pattern_br_a, imagePosA.br); - gl.uniform2fv(shader.u_pattern_tl_b, imagePosB.tl); - gl.uniform2fv(shader.u_pattern_br_b, imagePosB.br); - gl.uniform1f(shader.u_fade, image.t); - gl.uniform1f(shader.u_opacity, layer.paint['line-opacity']); - - gl.uniform1f(shader.u_extra, extra); - gl.uniform1f(shader.u_offset, -layer.paint['line-offset']); - gl.uniformMatrix2fv(shader.u_antialiasingmatrix, false, antialiasingMatrix); - - } else { - shader = painter.lineShader; - gl.switchShader(shader); +/** + * Rotates a matrix by the given angle around the Z axis not using SIMD + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +mat4.scalar.rotateZ = function (out, a, rad) { + var s = Math.sin(rad), + c = Math.cos(rad), + a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3], + a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7]; - gl.uniform2fv(shader.u_linewidth, [ outset, inset ]); - gl.uniform1f(shader.u_blur, blur); - gl.uniform1f(shader.u_extra, extra); - gl.uniform1f(shader.u_offset, -layer.paint['line-offset']); - gl.uniformMatrix2fv(shader.u_antialiasingmatrix, false, antialiasingMatrix); - gl.uniform4fv(shader.u_color, color); + if (a !== out) { // If the source and destination differ, copy the unchanged last row + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; } - for (var k = 0; k < coords.length; k++) { - var coord = coords[k]; - var tile = source.getTile(coord); - - var elementGroups = tile.getElementGroups(layer, 'line'); - if (!elementGroups) continue; - - painter.enableTileClippingMask(coord); - - // set uniforms that are different for each tile - var posMatrix = painter.translatePosMatrix(painter.calculatePosMatrix(coord, source.maxzoom), tile, layer.paint['line-translate'], layer.paint['line-translate-anchor']); - - gl.setPosMatrix(posMatrix); - gl.setExMatrix(painter.transform.exMatrix); - var ratio = 1 / tile.pixelsToTileUnits(1, painter.transform.zoom); - - if (dasharray) { - var widthA = posA.width * dasharray.fromScale; - var widthB = posB.width * dasharray.toScale; - var scaleA = [1 / tile.pixelsToTileUnits(widthA, painter.transform.tileZoom), -posA.height / 2]; - var scaleB = [1 / tile.pixelsToTileUnits(widthB, painter.transform.tileZoom), -posB.height / 2]; - var gamma = painter.lineAtlas.width / (Math.min(widthA, widthB) * 256 * browser.devicePixelRatio) / 2; - gl.uniform1f(shader.u_ratio, ratio); - gl.uniform2fv(shader.u_patternscale_a, scaleA); - gl.uniform2fv(shader.u_patternscale_b, scaleB); - gl.uniform1f(shader.u_sdfgamma, gamma); - - } else if (image) { - gl.uniform1f(shader.u_ratio, ratio); - gl.uniform2fv(shader.u_pattern_size_a, [ - tile.pixelsToTileUnits(imagePosA.size[0] * image.fromScale, painter.transform.tileZoom), - imagePosB.size[1] - ]); - gl.uniform2fv(shader.u_pattern_size_b, [ - tile.pixelsToTileUnits(imagePosB.size[0] * image.toScale, painter.transform.tileZoom), - imagePosB.size[1] - ]); - - } else { - gl.uniform1f(shader.u_ratio, ratio); - } - - var vertex = tile.buffers.lineVertex; - vertex.bind(gl); - var element = tile.buffers.lineElement; - element.bind(gl); + // Perform axis-specific matrix multiplication + out[0] = a00 * c + a10 * s; + out[1] = a01 * c + a11 * s; + out[2] = a02 * c + a12 * s; + out[3] = a03 * c + a13 * s; + out[4] = a10 * c - a00 * s; + out[5] = a11 * c - a01 * s; + out[6] = a12 * c - a02 * s; + out[7] = a13 * c - a03 * s; + return out; +}; - for (var i = 0; i < elementGroups.groups.length; i++) { - var group = elementGroups.groups[i]; - var vtxOffset = group.vertexStartIndex * vertex.itemSize; - gl.vertexAttribPointer(shader.a_pos, 2, gl.SHORT, false, 8, vtxOffset + 0); - gl.vertexAttribPointer(shader.a_data, 4, gl.BYTE, false, 8, vtxOffset + 4); +/** + * Rotates a matrix by the given angle around the Z axis using SIMD + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +mat4.SIMD.rotateZ = function (out, a, rad) { + var s = SIMD.Float32x4.splat(Math.sin(rad)), + c = SIMD.Float32x4.splat(Math.cos(rad)); - var count = group.elementLength * 3; - var elementOffset = group.elementStartIndex * element.itemSize; - gl.drawElements(gl.TRIANGLES, count, gl.UNSIGNED_SHORT, elementOffset); - } + if (a !== out) { // If the source and destination differ, copy the unchanged last row + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; } + // Perform axis-specific matrix multiplication + var a_0 = SIMD.Float32x4.load(a, 0); + var a_1 = SIMD.Float32x4.load(a, 4); + SIMD.Float32x4.store(out, 0, + SIMD.Float32x4.add(SIMD.Float32x4.mul(a_0, c), SIMD.Float32x4.mul(a_1, s))); + SIMD.Float32x4.store(out, 4, + SIMD.Float32x4.sub(SIMD.Float32x4.mul(a_1, c), SIMD.Float32x4.mul(a_0, s))); + return out; }; -},{"../util/browser":102,"../util/util":113,"gl-matrix":123}],37:[function(require,module,exports){ -'use strict'; - -var util = require('../util/util'); - -module.exports = drawRaster; - -function drawRaster(painter, source, layer, coords) { - if (painter.isOpaquePass) return; - - var gl = painter.gl; - - // Change depth function to prevent double drawing in areas where tiles overlap. - gl.depthFunc(gl.LESS); +/** + * Rotates a matrix by the given angle around the Z axis if SIMD available and enabled + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ + mat4.rotateZ = glMatrix.USE_SIMD ? mat4.SIMD.rotateZ : mat4.scalar.rotateZ; - for (var i = coords.length - 1; i >= 0; i--) { - drawRasterTile(painter, source, layer, coords[i]); - } +/** + * Creates a matrix from a vector translation + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, dest, vec); + * + * @param {mat4} out mat4 receiving operation result + * @param {vec3} v Translation vector + * @returns {mat4} out + */ +mat4.fromTranslation = function(out, v) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; + return out; +} - gl.depthFunc(gl.LEQUAL); +/** + * Creates a matrix from a vector scaling + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.scale(dest, dest, vec); + * + * @param {mat4} out mat4 receiving operation result + * @param {vec3} v Scaling vector + * @returns {mat4} out + */ +mat4.fromScaling = function(out, v) { + out[0] = v[0]; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = v[1]; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = v[2]; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; } -function drawRasterTile(painter, source, layer, coord) { +/** + * Creates a matrix from a given angle around a given axis + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.rotate(dest, dest, rad, axis); + * + * @param {mat4} out mat4 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @param {vec3} axis the axis to rotate around + * @returns {mat4} out + */ +mat4.fromRotation = function(out, rad, axis) { + var x = axis[0], y = axis[1], z = axis[2], + len = Math.sqrt(x * x + y * y + z * z), + s, c, t; - painter.setDepthSublayer(0); + if (Math.abs(len) < glMatrix.EPSILON) { return null; } - var gl = painter.gl; + len = 1 / len; + x *= len; + y *= len; + z *= len; - gl.disable(gl.STENCIL_TEST); + s = Math.sin(rad); + c = Math.cos(rad); + t = 1 - c; - var tile = source.getTile(coord); - var posMatrix = painter.calculatePosMatrix(coord, source.maxzoom); + // Perform rotation-specific matrix multiplication + out[0] = x * x * t + c; + out[1] = y * x * t + z * s; + out[2] = z * x * t - y * s; + out[3] = 0; + out[4] = x * y * t - z * s; + out[5] = y * y * t + c; + out[6] = z * y * t + x * s; + out[7] = 0; + out[8] = x * z * t + y * s; + out[9] = y * z * t - x * s; + out[10] = z * z * t + c; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +} - var shader = painter.rasterShader; - gl.switchShader(shader, posMatrix); +/** + * Creates a matrix from the given angle around the X axis + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.rotateX(dest, dest, rad); + * + * @param {mat4} out mat4 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +mat4.fromXRotation = function(out, rad) { + var s = Math.sin(rad), + c = Math.cos(rad); - // color parameters - gl.uniform1f(shader.u_brightness_low, layer.paint['raster-brightness-min']); - gl.uniform1f(shader.u_brightness_high, layer.paint['raster-brightness-max']); - gl.uniform1f(shader.u_saturation_factor, saturationFactor(layer.paint['raster-saturation'])); - gl.uniform1f(shader.u_contrast_factor, contrastFactor(layer.paint['raster-contrast'])); - gl.uniform3fv(shader.u_spin_weights, spinWeights(layer.paint['raster-hue-rotate'])); + // Perform axis-specific matrix multiplication + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = c; + out[6] = s; + out[7] = 0; + out[8] = 0; + out[9] = -s; + out[10] = c; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +} - var parentTile = tile.source && tile.source._pyramid.findLoadedParent(coord, 0, {}), - opacities = getOpacities(tile, parentTile, layer, painter.transform); +/** + * Creates a matrix from the given angle around the Y axis + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.rotateY(dest, dest, rad); + * + * @param {mat4} out mat4 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +mat4.fromYRotation = function(out, rad) { + var s = Math.sin(rad), + c = Math.cos(rad); - var parentScaleBy, parentTL; - - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, tile.texture); - - if (parentTile) { - gl.activeTexture(gl.TEXTURE1); - gl.bindTexture(gl.TEXTURE_2D, parentTile.texture); - - parentScaleBy = Math.pow(2, parentTile.coord.z - tile.coord.z); - parentTL = [tile.coord.x * parentScaleBy % 1, tile.coord.y * parentScaleBy % 1]; - } else { - opacities[1] = 0; - } - - // cross-fade parameters - gl.uniform2fv(shader.u_tl_parent, parentTL || [0, 0]); - gl.uniform1f(shader.u_scale_parent, parentScaleBy || 1); - gl.uniform1f(shader.u_buffer_scale, 1); - gl.uniform1f(shader.u_opacity0, opacities[0]); - gl.uniform1f(shader.u_opacity1, opacities[1]); - gl.uniform1i(shader.u_image0, 0); - gl.uniform1i(shader.u_image1, 1); - - gl.bindBuffer(gl.ARRAY_BUFFER, tile.boundsBuffer || painter.tileExtentBuffer); - - gl.vertexAttribPointer(shader.a_pos, 2, gl.SHORT, false, 8, 0); - gl.vertexAttribPointer(shader.a_texture_pos, 2, gl.SHORT, false, 8, 4); - gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + // Perform axis-specific matrix multiplication + out[0] = c; + out[1] = 0; + out[2] = -s; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = s; + out[9] = 0; + out[10] = c; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; } -function spinWeights(angle) { - angle *= Math.PI / 180; - var s = Math.sin(angle); - var c = Math.cos(angle); - return [ - (2 * c + 1) / 3, - (-Math.sqrt(3) * s - c + 1) / 3, - (Math.sqrt(3) * s - c + 1) / 3 - ]; -} +/** + * Creates a matrix from the given angle around the Z axis + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.rotateZ(dest, dest, rad); + * + * @param {mat4} out mat4 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +mat4.fromZRotation = function(out, rad) { + var s = Math.sin(rad), + c = Math.cos(rad); -function contrastFactor(contrast) { - return contrast > 0 ? - 1 / (1 - contrast) : - 1 + contrast; + // Perform axis-specific matrix multiplication + out[0] = c; + out[1] = s; + out[2] = 0; + out[3] = 0; + out[4] = -s; + out[5] = c; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; } -function saturationFactor(saturation) { - return saturation > 0 ? - 1 - 1 / (1.001 - saturation) : - -saturation; -} +/** + * Creates a matrix from a quaternion rotation and vector translation + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, vec); + * var quatMat = mat4.create(); + * quat4.toMat4(quat, quatMat); + * mat4.multiply(dest, quatMat); + * + * @param {mat4} out mat4 receiving operation result + * @param {quat4} q Rotation quaternion + * @param {vec3} v Translation vector + * @returns {mat4} out + */ +mat4.fromRotationTranslation = function (out, q, v) { + // Quaternion math + var x = q[0], y = q[1], z = q[2], w = q[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, -function getOpacities(tile, parentTile, layer, transform) { - var opacity = [1, 0]; - var fadeDuration = layer.paint['raster-fade-duration']; + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; - if (tile.source && fadeDuration > 0) { - var now = new Date().getTime(); + out[0] = 1 - (yy + zz); + out[1] = xy + wz; + out[2] = xz - wy; + out[3] = 0; + out[4] = xy - wz; + out[5] = 1 - (xx + zz); + out[6] = yz + wx; + out[7] = 0; + out[8] = xz + wy; + out[9] = yz - wx; + out[10] = 1 - (xx + yy); + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; - var sinceTile = (now - tile.timeAdded) / fadeDuration; - var sinceParent = parentTile ? (now - parentTile.timeAdded) / fadeDuration : -1; + return out; +}; - var idealZ = tile.source._pyramid.coveringZoomLevel(transform); - var parentFurther = parentTile ? Math.abs(parentTile.coord.z - idealZ) > Math.abs(tile.coord.z - idealZ) : false; +/** + * Returns the translation vector component of a transformation + * matrix. If a matrix is built with fromRotationTranslation, + * the returned vector will be the same as the translation vector + * originally supplied. + * @param {vec3} out Vector to receive translation component + * @param {mat4} mat Matrix to be decomposed (input) + * @return {vec3} out + */ +mat4.getTranslation = function (out, mat) { + out[0] = mat[12]; + out[1] = mat[13]; + out[2] = mat[14]; - if (!parentTile || parentFurther) { - // if no parent or parent is older - opacity[0] = util.clamp(sinceTile, 0, 1); - opacity[1] = 1 - opacity[0]; - } else { - // parent is younger, zooming out - opacity[0] = util.clamp(1 - sinceParent, 0, 1); - opacity[1] = 1 - opacity[0]; - } - } + return out; +}; - var op = layer.paint['raster-opacity']; - opacity[0] *= op; - opacity[1] *= op; +/** + * Returns a quaternion representing the rotational component + * of a transformation matrix. If a matrix is built with + * fromRotationTranslation, the returned quaternion will be the + * same as the quaternion originally supplied. + * @param {quat} out Quaternion to receive the rotation component + * @param {mat4} mat Matrix to be decomposed (input) + * @return {quat} out + */ +mat4.getRotation = function (out, mat) { + // Algorithm taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm + var trace = mat[0] + mat[5] + mat[10]; + var S = 0; + + if (trace > 0) { + S = Math.sqrt(trace + 1.0) * 2; + out[3] = 0.25 * S; + out[0] = (mat[6] - mat[9]) / S; + out[1] = (mat[8] - mat[2]) / S; + out[2] = (mat[1] - mat[4]) / S; + } else if ((mat[0] > mat[5])&(mat[0] > mat[10])) { + S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2; + out[3] = (mat[6] - mat[9]) / S; + out[0] = 0.25 * S; + out[1] = (mat[1] + mat[4]) / S; + out[2] = (mat[8] + mat[2]) / S; + } else if (mat[5] > mat[10]) { + S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2; + out[3] = (mat[8] - mat[2]) / S; + out[0] = (mat[1] + mat[4]) / S; + out[1] = 0.25 * S; + out[2] = (mat[6] + mat[9]) / S; + } else { + S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2; + out[3] = (mat[1] - mat[4]) / S; + out[0] = (mat[8] + mat[2]) / S; + out[1] = (mat[6] + mat[9]) / S; + out[2] = 0.25 * S; + } - return opacity; -} + return out; +}; -},{"../util/util":113}],38:[function(require,module,exports){ -'use strict'; +/** + * Creates a matrix from a quaternion rotation, vector translation and vector scale + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, vec); + * var quatMat = mat4.create(); + * quat4.toMat4(quat, quatMat); + * mat4.multiply(dest, quatMat); + * mat4.scale(dest, scale) + * + * @param {mat4} out mat4 receiving operation result + * @param {quat4} q Rotation quaternion + * @param {vec3} v Translation vector + * @param {vec3} s Scaling vector + * @returns {mat4} out + */ +mat4.fromRotationTranslationScale = function (out, q, v, s) { + // Quaternion math + var x = q[0], y = q[1], z = q[2], w = q[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, -var mat4 = require('gl-matrix').mat4; + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2, + sx = s[0], + sy = s[1], + sz = s[2]; -var browser = require('../util/browser'); -var drawCollisionDebug = require('./draw_collision_debug'); -var util = require('../util/util'); + out[0] = (1 - (yy + zz)) * sx; + out[1] = (xy + wz) * sx; + out[2] = (xz - wy) * sx; + out[3] = 0; + out[4] = (xy - wz) * sy; + out[5] = (1 - (xx + zz)) * sy; + out[6] = (yz + wx) * sy; + out[7] = 0; + out[8] = (xz + wy) * sz; + out[9] = (yz - wx) * sz; + out[10] = (1 - (xx + yy)) * sz; + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; -module.exports = drawSymbols; + return out; +}; -function drawSymbols(painter, source, layer, coords) { - if (painter.isOpaquePass) return; +/** + * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, vec); + * mat4.translate(dest, origin); + * var quatMat = mat4.create(); + * quat4.toMat4(quat, quatMat); + * mat4.multiply(dest, quatMat); + * mat4.scale(dest, scale) + * mat4.translate(dest, negativeOrigin); + * + * @param {mat4} out mat4 receiving operation result + * @param {quat4} q Rotation quaternion + * @param {vec3} v Translation vector + * @param {vec3} s Scaling vector + * @param {vec3} o The origin vector around which to scale and rotate + * @returns {mat4} out + */ +mat4.fromRotationTranslationScaleOrigin = function (out, q, v, s, o) { + // Quaternion math + var x = q[0], y = q[1], z = q[2], w = q[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, - var drawAcrossEdges = !(layer.layout['text-allow-overlap'] || layer.layout['icon-allow-overlap'] || - layer.layout['text-ignore-placement'] || layer.layout['icon-ignore-placement']); + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2, - var gl = painter.gl; + sx = s[0], + sy = s[1], + sz = s[2], - // Disable the stencil test so that labels aren't clipped to tile boundaries. - // - // Layers with features that may be drawn overlapping aren't clipped. These - // layers are sorted in the y direction, and to draw the correct ordering near - // tile edges the icons are included in both tiles and clipped when drawing. - if (drawAcrossEdges) { - gl.disable(gl.STENCIL_TEST); - } else { - gl.enable(gl.STENCIL_TEST); - } - - painter.setDepthSublayer(0); - painter.depthMask(false); - gl.disable(gl.DEPTH_TEST); - - var tile, elementGroups, posMatrix; + ox = o[0], + oy = o[1], + oz = o[2]; - for (var i = 0; i < coords.length; i++) { - tile = source.getTile(coords[i]); + out[0] = (1 - (yy + zz)) * sx; + out[1] = (xy + wz) * sx; + out[2] = (xz - wy) * sx; + out[3] = 0; + out[4] = (xy - wz) * sy; + out[5] = (1 - (xx + zz)) * sy; + out[6] = (yz + wx) * sy; + out[7] = 0; + out[8] = (xz + wy) * sz; + out[9] = (yz - wx) * sz; + out[10] = (1 - (xx + yy)) * sz; + out[11] = 0; + out[12] = v[0] + ox - (out[0] * ox + out[4] * oy + out[8] * oz); + out[13] = v[1] + oy - (out[1] * ox + out[5] * oy + out[9] * oz); + out[14] = v[2] + oz - (out[2] * ox + out[6] * oy + out[10] * oz); + out[15] = 1; - if (!tile.buffers) continue; - elementGroups = tile.elementGroups[layer.ref || layer.id]; - if (!elementGroups) continue; - if (!elementGroups.icon.groups.length) continue; + return out; +}; - posMatrix = painter.calculatePosMatrix(coords[i], source.maxzoom); - painter.enableTileClippingMask(coords[i]); - drawSymbol(painter, layer, posMatrix, tile, elementGroups.icon, 'icon', elementGroups.sdfIcons, elementGroups.iconsNeedLinear); - } +/** + * Calculates a 4x4 matrix from the given quaternion + * + * @param {mat4} out mat4 receiving operation result + * @param {quat} q Quaternion to create matrix from + * + * @returns {mat4} out + */ +mat4.fromQuat = function (out, q) { + var x = q[0], y = q[1], z = q[2], w = q[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, - for (var j = 0; j < coords.length; j++) { - tile = source.getTile(coords[j]); + xx = x * x2, + yx = y * x2, + yy = y * y2, + zx = z * x2, + zy = z * y2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; - if (!tile.buffers) continue; - elementGroups = tile.elementGroups[layer.ref || layer.id]; - if (!elementGroups) continue; - if (!elementGroups.glyph.groups.length) continue; + out[0] = 1 - yy - zz; + out[1] = yx + wz; + out[2] = zx - wy; + out[3] = 0; - posMatrix = painter.calculatePosMatrix(coords[j], source.maxzoom); - painter.enableTileClippingMask(coords[j]); - drawSymbol(painter, layer, posMatrix, tile, elementGroups.glyph, 'text', true, false); - } + out[4] = yx - wz; + out[5] = 1 - xx - zz; + out[6] = zy + wx; + out[7] = 0; - gl.enable(gl.DEPTH_TEST); + out[8] = zx + wy; + out[9] = zy - wx; + out[10] = 1 - xx - yy; + out[11] = 0; - drawCollisionDebug(painter, source, layer, coords); -} + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; -var defaultSizes = { - icon: 1, - text: 24 + return out; }; -function drawSymbol(painter, layer, posMatrix, tile, elementGroups, prefix, sdf, iconsNeedLinear) { - var gl = painter.gl; +/** + * Generates a frustum matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {Number} left Left bound of the frustum + * @param {Number} right Right bound of the frustum + * @param {Number} bottom Bottom bound of the frustum + * @param {Number} top Top bound of the frustum + * @param {Number} near Near bound of the frustum + * @param {Number} far Far bound of the frustum + * @returns {mat4} out + */ +mat4.frustum = function (out, left, right, bottom, top, near, far) { + var rl = 1 / (right - left), + tb = 1 / (top - bottom), + nf = 1 / (near - far); + out[0] = (near * 2) * rl; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = (near * 2) * tb; + out[6] = 0; + out[7] = 0; + out[8] = (right + left) * rl; + out[9] = (top + bottom) * tb; + out[10] = (far + near) * nf; + out[11] = -1; + out[12] = 0; + out[13] = 0; + out[14] = (far * near * 2) * nf; + out[15] = 0; + return out; +}; - posMatrix = painter.translatePosMatrix(posMatrix, tile, layer.paint[prefix + '-translate'], layer.paint[prefix + '-translate-anchor']); +/** + * Generates a perspective projection matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {number} fovy Vertical field of view in radians + * @param {number} aspect Aspect ratio. typically viewport width/height + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @returns {mat4} out + */ +mat4.perspective = function (out, fovy, aspect, near, far) { + var f = 1.0 / Math.tan(fovy / 2), + nf = 1 / (near - far); + out[0] = f / aspect; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = f; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = (far + near) * nf; + out[11] = -1; + out[12] = 0; + out[13] = 0; + out[14] = (2 * far * near) * nf; + out[15] = 0; + return out; +}; - var tr = painter.transform; - var alignedWithMap = layer.layout[prefix + '-rotation-alignment'] === 'map'; - var skewed = alignedWithMap; - var exMatrix, s, gammaScale; +/** + * Generates a perspective projection matrix with the given field of view. + * This is primarily useful for generating projection matrices to be used + * with the still experiemental WebVR API. + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @returns {mat4} out + */ +mat4.perspectiveFromFieldOfView = function (out, fov, near, far) { + var upTan = Math.tan(fov.upDegrees * Math.PI/180.0), + downTan = Math.tan(fov.downDegrees * Math.PI/180.0), + leftTan = Math.tan(fov.leftDegrees * Math.PI/180.0), + rightTan = Math.tan(fov.rightDegrees * Math.PI/180.0), + xScale = 2.0 / (leftTan + rightTan), + yScale = 2.0 / (upTan + downTan); - if (skewed) { - exMatrix = mat4.create(); - s = tile.pixelsToTileUnits(1, painter.transform.zoom); - gammaScale = 1 / Math.cos(tr._pitch); - } else { - exMatrix = mat4.clone(painter.transform.exMatrix); - s = painter.transform.altitude; - gammaScale = 1; - } - mat4.scale(exMatrix, exMatrix, [s, s, 1]); + out[0] = xScale; + out[1] = 0.0; + out[2] = 0.0; + out[3] = 0.0; + out[4] = 0.0; + out[5] = yScale; + out[6] = 0.0; + out[7] = 0.0; + out[8] = -((leftTan - rightTan) * xScale * 0.5); + out[9] = ((upTan - downTan) * yScale * 0.5); + out[10] = far / (near - far); + out[11] = -1.0; + out[12] = 0.0; + out[13] = 0.0; + out[14] = (far * near) / (near - far); + out[15] = 0.0; + return out; +} - var fontSize = layer.layout[prefix + '-size']; - var fontScale = fontSize / defaultSizes[prefix]; - mat4.scale(exMatrix, exMatrix, [ fontScale, fontScale, 1 ]); +/** + * Generates a orthogonal projection matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {number} left Left bound of the frustum + * @param {number} right Right bound of the frustum + * @param {number} bottom Bottom bound of the frustum + * @param {number} top Top bound of the frustum + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @returns {mat4} out + */ +mat4.ortho = function (out, left, right, bottom, top, near, far) { + var lr = 1 / (left - right), + bt = 1 / (bottom - top), + nf = 1 / (near - far); + out[0] = -2 * lr; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = -2 * bt; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 2 * nf; + out[11] = 0; + out[12] = (left + right) * lr; + out[13] = (top + bottom) * bt; + out[14] = (far + near) * nf; + out[15] = 1; + return out; +}; - // calculate how much longer the real world distance is at the top of the screen - // than at the middle of the screen. - var topedgelength = Math.sqrt(tr.height * tr.height / 4 * (1 + tr.altitude * tr.altitude)); - var x = tr.height / 2 * Math.tan(tr._pitch); - var extra = (topedgelength + x) / topedgelength - 1; +/** + * Generates a look-at matrix with the given eye position, focal point, and up axis + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {vec3} eye Position of the viewer + * @param {vec3} center Point the viewer is looking at + * @param {vec3} up vec3 pointing up + * @returns {mat4} out + */ +mat4.lookAt = function (out, eye, center, up) { + var x0, x1, x2, y0, y1, y2, z0, z1, z2, len, + eyex = eye[0], + eyey = eye[1], + eyez = eye[2], + upx = up[0], + upy = up[1], + upz = up[2], + centerx = center[0], + centery = center[1], + centerz = center[2]; - var text = prefix === 'text'; - var shader, vertex, elements, texsize; + if (Math.abs(eyex - centerx) < glMatrix.EPSILON && + Math.abs(eyey - centery) < glMatrix.EPSILON && + Math.abs(eyez - centerz) < glMatrix.EPSILON) { + return mat4.identity(out); + } - if (!text && !painter.style.sprite.loaded()) - return; + z0 = eyex - centerx; + z1 = eyey - centery; + z2 = eyez - centerz; - gl.activeTexture(gl.TEXTURE0); + len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); + z0 *= len; + z1 *= len; + z2 *= len; - if (sdf) { - shader = painter.sdfShader; + x0 = upy * z2 - upz * z1; + x1 = upz * z0 - upx * z2; + x2 = upx * z1 - upy * z0; + len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); + if (!len) { + x0 = 0; + x1 = 0; + x2 = 0; } else { - shader = painter.iconShader; + len = 1 / len; + x0 *= len; + x1 *= len; + x2 *= len; } - if (text) { - // use the fonstack used when parsing the tile, not the fontstack - // at the current zoom level (layout['text-font']). - var fontstack = elementGroups.fontstack; - var glyphAtlas = fontstack && painter.glyphSource.getGlyphAtlas(fontstack); - if (!glyphAtlas) return; + y0 = z1 * x2 - z2 * x1; + y1 = z2 * x0 - z0 * x2; + y2 = z0 * x1 - z1 * x0; - glyphAtlas.updateTexture(gl); - vertex = tile.buffers.glyphVertex; - elements = tile.buffers.glyphElement; - texsize = [glyphAtlas.width / 4, glyphAtlas.height / 4]; + len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); + if (!len) { + y0 = 0; + y1 = 0; + y2 = 0; } else { - var mapMoving = painter.options.rotating || painter.options.zooming; - var iconScaled = fontScale !== 1 || browser.devicePixelRatio !== painter.spriteAtlas.pixelRatio || iconsNeedLinear; - var iconTransformed = alignedWithMap || painter.transform.pitch; - painter.spriteAtlas.bind(gl, sdf || mapMoving || iconScaled || iconTransformed); - vertex = tile.buffers.iconVertex; - elements = tile.buffers.iconElement; - texsize = [painter.spriteAtlas.width / 4, painter.spriteAtlas.height / 4]; + len = 1 / len; + y0 *= len; + y1 *= len; + y2 *= len; } - gl.switchShader(shader, posMatrix, exMatrix); - gl.uniform1i(shader.u_texture, 0); - gl.uniform2fv(shader.u_texsize, texsize); - gl.uniform1i(shader.u_skewed, skewed); - gl.uniform1f(shader.u_extra, extra); - - // adjust min/max zooms for variable font sizes - var zoomAdjust = Math.log(fontSize / elementGroups.adjustedSize) / Math.LN2 || 0; - - - gl.uniform1f(shader.u_zoom, (painter.transform.zoom - zoomAdjust) * 10); // current zoom level - - var f = painter.frameHistory.getFadeProperties(300); - gl.uniform1f(shader.u_fadedist, f.fadedist * 10); - gl.uniform1f(shader.u_minfadezoom, Math.floor(f.minfadezoom * 10)); - gl.uniform1f(shader.u_maxfadezoom, Math.floor(f.maxfadezoom * 10)); - gl.uniform1f(shader.u_fadezoom, (painter.transform.zoom + f.bump) * 10); - - var group, offset, count, elementOffset; - - elements.bind(gl); + out[0] = x0; + out[1] = y0; + out[2] = z0; + out[3] = 0; + out[4] = x1; + out[5] = y1; + out[6] = z1; + out[7] = 0; + out[8] = x2; + out[9] = y2; + out[10] = z2; + out[11] = 0; + out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); + out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); + out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); + out[15] = 1; - if (sdf) { - var sdfPx = 8; - var blurOffset = 1.19; - var haloOffset = 6; - var gamma = 0.105 * defaultSizes[prefix] / fontSize / browser.devicePixelRatio; + return out; +}; - if (layer.paint[prefix + '-halo-width']) { - var haloColor = util.premultiply(layer.paint[prefix + '-halo-color'], layer.paint[prefix + '-opacity']); +/** + * Returns a string representation of a mat4 + * + * @param {mat4} mat matrix to represent as a string + * @returns {String} string representation of the matrix + */ +mat4.str = function (a) { + return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + + a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + + a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')'; +}; - // Draw halo underneath the text. - gl.uniform1f(shader.u_gamma, (layer.paint[prefix + '-halo-blur'] * blurOffset / fontScale / sdfPx + gamma) * gammaScale); - gl.uniform4fv(shader.u_color, haloColor); - gl.uniform1f(shader.u_buffer, (haloOffset - layer.paint[prefix + '-halo-width'] / fontScale) / sdfPx); +/** + * Returns Frobenius norm of a mat4 + * + * @param {mat4} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ +mat4.frob = function (a) { + return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2) )) +}; - for (var j = 0; j < elementGroups.groups.length; j++) { - group = elementGroups.groups[j]; - offset = group.vertexStartIndex * vertex.itemSize; - vertex.bind(gl); - vertex.setAttribPointers(gl, shader, offset); +/** + * Adds two mat4's + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the first operand + * @param {mat4} b the second operand + * @returns {mat4} out + */ +mat4.add = function(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + out[6] = a[6] + b[6]; + out[7] = a[7] + b[7]; + out[8] = a[8] + b[8]; + out[9] = a[9] + b[9]; + out[10] = a[10] + b[10]; + out[11] = a[11] + b[11]; + out[12] = a[12] + b[12]; + out[13] = a[13] + b[13]; + out[14] = a[14] + b[14]; + out[15] = a[15] + b[15]; + return out; +}; - count = group.elementLength * 3; - elementOffset = group.elementStartIndex * elements.itemSize; - gl.drawElements(gl.TRIANGLES, count, gl.UNSIGNED_SHORT, elementOffset); - } - } +/** + * Subtracts matrix b from matrix a + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the first operand + * @param {mat4} b the second operand + * @returns {mat4} out + */ +mat4.subtract = function(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + out[4] = a[4] - b[4]; + out[5] = a[5] - b[5]; + out[6] = a[6] - b[6]; + out[7] = a[7] - b[7]; + out[8] = a[8] - b[8]; + out[9] = a[9] - b[9]; + out[10] = a[10] - b[10]; + out[11] = a[11] - b[11]; + out[12] = a[12] - b[12]; + out[13] = a[13] - b[13]; + out[14] = a[14] - b[14]; + out[15] = a[15] - b[15]; + return out; +}; - var color = util.premultiply(layer.paint[prefix + '-color'], layer.paint[prefix + '-opacity']); - gl.uniform1f(shader.u_gamma, gamma * gammaScale); - gl.uniform4fv(shader.u_color, color); - gl.uniform1f(shader.u_buffer, (256 - 64) / 256); +/** + * Alias for {@link mat4.subtract} + * @function + */ +mat4.sub = mat4.subtract; - for (var i = 0; i < elementGroups.groups.length; i++) { - group = elementGroups.groups[i]; - offset = group.vertexStartIndex * vertex.itemSize; - vertex.bind(gl); - vertex.setAttribPointers(gl, shader, offset); +/** + * Multiply each element of the matrix by a scalar. + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to scale + * @param {Number} b amount to scale the matrix's elements by + * @returns {mat4} out + */ +mat4.multiplyScalar = function(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + out[4] = a[4] * b; + out[5] = a[5] * b; + out[6] = a[6] * b; + out[7] = a[7] * b; + out[8] = a[8] * b; + out[9] = a[9] * b; + out[10] = a[10] * b; + out[11] = a[11] * b; + out[12] = a[12] * b; + out[13] = a[13] * b; + out[14] = a[14] * b; + out[15] = a[15] * b; + return out; +}; - count = group.elementLength * 3; - elementOffset = group.elementStartIndex * elements.itemSize; - gl.drawElements(gl.TRIANGLES, count, gl.UNSIGNED_SHORT, elementOffset); - } +/** + * Adds two mat4's after multiplying each element of the second operand by a scalar value. + * + * @param {mat4} out the receiving vector + * @param {mat4} a the first operand + * @param {mat4} b the second operand + * @param {Number} scale the amount to scale b's elements by before adding + * @returns {mat4} out + */ +mat4.multiplyScalarAndAdd = function(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + out[2] = a[2] + (b[2] * scale); + out[3] = a[3] + (b[3] * scale); + out[4] = a[4] + (b[4] * scale); + out[5] = a[5] + (b[5] * scale); + out[6] = a[6] + (b[6] * scale); + out[7] = a[7] + (b[7] * scale); + out[8] = a[8] + (b[8] * scale); + out[9] = a[9] + (b[9] * scale); + out[10] = a[10] + (b[10] * scale); + out[11] = a[11] + (b[11] * scale); + out[12] = a[12] + (b[12] * scale); + out[13] = a[13] + (b[13] * scale); + out[14] = a[14] + (b[14] * scale); + out[15] = a[15] + (b[15] * scale); + return out; +}; - } else { - gl.uniform1f(shader.u_opacity, layer.paint['icon-opacity']); - for (var k = 0; k < elementGroups.groups.length; k++) { - group = elementGroups.groups[k]; - offset = group.vertexStartIndex * vertex.itemSize; - vertex.bind(gl); - vertex.setAttribPointers(gl, shader, offset); +/** + * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) + * + * @param {mat4} a The first matrix. + * @param {mat4} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ +mat4.exactEquals = function (a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && + a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && + a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && + a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15]; +}; - count = group.elementLength * 3; - elementOffset = group.elementStartIndex * elements.itemSize; - gl.drawElements(gl.TRIANGLES, count, gl.UNSIGNED_SHORT, elementOffset); - } - } -} +/** + * Returns whether or not the matrices have approximately the same elements in the same position. + * + * @param {mat4} a The first matrix. + * @param {mat4} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ +mat4.equals = function (a, b) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], + a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7], + a8 = a[8], a9 = a[9], a10 = a[10], a11 = a[11], + a12 = a[12], a13 = a[13], a14 = a[14], a15 = a[15]; -},{"../util/browser":102,"../util/util":113,"./draw_collision_debug":33,"gl-matrix":123}],39:[function(require,module,exports){ -'use strict'; + var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], + b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7], + b8 = b[8], b9 = b[9], b10 = b[10], b11 = b[11], + b12 = b[12], b13 = b[13], b14 = b[14], b15 = b[15]; -module.exports = FrameHistory; + return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && + Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) && + Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) && + Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) && + Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) && + Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)) && + Math.abs(a6 - b6) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a6), Math.abs(b6)) && + Math.abs(a7 - b7) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a7), Math.abs(b7)) && + Math.abs(a8 - b8) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a8), Math.abs(b8)) && + Math.abs(a9 - b9) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a9), Math.abs(b9)) && + Math.abs(a10 - b10) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a10), Math.abs(b10)) && + Math.abs(a11 - b11) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a11), Math.abs(b11)) && + Math.abs(a12 - b12) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a12), Math.abs(b12)) && + Math.abs(a13 - b13) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a13), Math.abs(b13)) && + Math.abs(a14 - b14) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a14), Math.abs(b14)) && + Math.abs(a15 - b15) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a15), Math.abs(b15))); +}; -function FrameHistory() { - this.frameHistory = []; -} -FrameHistory.prototype.getFadeProperties = function(duration) { - if (duration === undefined) duration = 300; - var currentTime = (new Date()).getTime(); - // Remove frames until only one is outside the duration, or until there are only three - while (this.frameHistory.length > 3 && this.frameHistory[1].time + duration < currentTime) { - this.frameHistory.shift(); - } +module.exports = mat4; - if (this.frameHistory[1].time + duration < currentTime) { - this.frameHistory[0].z = this.frameHistory[1].z; - } +},{"./common.js":30}],35:[function(require,module,exports){ +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - var frameLen = this.frameHistory.length; - if (frameLen < 3) console.warn('there should never be less than three frames in the history'); +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: - // Find the range of zoom levels we want to fade between - var startingZ = this.frameHistory[0].z, - lastFrame = this.frameHistory[frameLen - 1], - endingZ = lastFrame.z, - lowZ = Math.min(startingZ, endingZ), - highZ = Math.max(startingZ, endingZ); +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - // Calculate the speed of zooming, and how far it would zoom in terms of zoom levels in one duration - var zoomDiff = lastFrame.z - this.frameHistory[1].z, - timeDiff = lastFrame.time - this.frameHistory[1].time; - var fadedist = zoomDiff / (timeDiff / duration); +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. */ - if (isNaN(fadedist)) console.warn('fadedist should never be NaN'); +var glMatrix = require("./common.js"); +var mat3 = require("./mat3.js"); +var vec3 = require("./vec3.js"); +var vec4 = require("./vec4.js"); - // At end of a zoom when the zoom stops changing continue pretending to zoom at that speed - // bump is how much farther it would have been if it had continued zooming at the same rate - var bump = (currentTime - lastFrame.time) / duration * fadedist; +/** + * @class Quaternion + * @name quat + */ +var quat = {}; - return { - fadedist: fadedist, - minfadezoom: lowZ, - maxfadezoom: highZ, - bump: bump - }; +/** + * Creates a new identity quat + * + * @returns {quat} a new quaternion + */ +quat.create = function() { + var out = new glMatrix.ARRAY_TYPE(4); + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; }; -// Record frame history that will be used to calculate fading params -FrameHistory.prototype.record = function(zoom) { - var currentTime = (new Date()).getTime(); +/** + * Sets a quaternion to represent the shortest rotation from one + * vector to another. + * + * Both vectors are assumed to be unit length. + * + * @param {quat} out the receiving quaternion. + * @param {vec3} a the initial vector + * @param {vec3} b the destination vector + * @returns {quat} out + */ +quat.rotationTo = (function() { + var tmpvec3 = vec3.create(); + var xUnitVec3 = vec3.fromValues(1,0,0); + var yUnitVec3 = vec3.fromValues(0,1,0); - // first frame ever - if (!this.frameHistory.length) { - this.frameHistory.push({time: 0, z: zoom }, {time: 0, z: zoom }); - } + return function(out, a, b) { + var dot = vec3.dot(a, b); + if (dot < -0.999999) { + vec3.cross(tmpvec3, xUnitVec3, a); + if (vec3.length(tmpvec3) < 0.000001) + vec3.cross(tmpvec3, yUnitVec3, a); + vec3.normalize(tmpvec3, tmpvec3); + quat.setAxisAngle(out, tmpvec3, Math.PI); + return out; + } else if (dot > 0.999999) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; + } else { + vec3.cross(tmpvec3, a, b); + out[0] = tmpvec3[0]; + out[1] = tmpvec3[1]; + out[2] = tmpvec3[2]; + out[3] = 1 + dot; + return quat.normalize(out, out); + } + }; +})(); - if (this.frameHistory.length === 2 || this.frameHistory[this.frameHistory.length - 1].z !== zoom) { - this.frameHistory.push({ - time: currentTime, - z: zoom - }); - } -}; +/** + * Sets the specified quaternion with values corresponding to the given + * axes. Each axis is a vec3 and is expected to be unit length and + * perpendicular to all other specified axes. + * + * @param {vec3} view the vector representing the viewing direction + * @param {vec3} right the vector representing the local "right" direction + * @param {vec3} up the vector representing the local "up" direction + * @returns {quat} out + */ +quat.setAxes = (function() { + var matr = mat3.create(); -},{}],40:[function(require,module,exports){ -'use strict'; + return function(out, view, right, up) { + matr[0] = right[0]; + matr[3] = right[1]; + matr[6] = right[2]; -var shaders = require('./shaders'); -var util = require('../util/util'); + matr[1] = up[0]; + matr[4] = up[1]; + matr[7] = up[2]; -exports.extend = function(context) { - var origLineWidth = context.lineWidth, - lineWidthRange = context.getParameter(context.ALIASED_LINE_WIDTH_RANGE); + matr[2] = -view[0]; + matr[5] = -view[1]; + matr[8] = -view[2]; - context.lineWidth = function(width) { - origLineWidth.call(context, util.clamp(width, lineWidthRange[0], lineWidthRange[1])); + return quat.normalize(out, quat.fromMat3(out, matr)); }; +})(); - context.getShader = function(name, type) { - var kind = type === this.FRAGMENT_SHADER ? 'fragment' : 'vertex'; - if (!shaders[name] || !shaders[name][kind]) { - throw new Error("Could not find shader " + name); - } - - var shader = this.createShader(type); - var shaderSource = shaders[name][kind]; +/** + * Creates a new quat initialized with values from an existing quaternion + * + * @param {quat} a quaternion to clone + * @returns {quat} a new quaternion + * @function + */ +quat.clone = vec4.clone; - if (typeof orientation === 'undefined') { - // only use highp precision on mobile browsers - shaderSource = shaderSource.replace(/ highp /g, ' '); - } +/** + * Creates a new quat initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {quat} a new quaternion + * @function + */ +quat.fromValues = vec4.fromValues; - this.shaderSource(shader, shaderSource); - this.compileShader(shader); - if (!this.getShaderParameter(shader, this.COMPILE_STATUS)) { - throw new Error(this.getShaderInfoLog(shader)); - } - return shader; - }; +/** + * Copy the values from one quat to another + * + * @param {quat} out the receiving quaternion + * @param {quat} a the source quaternion + * @returns {quat} out + * @function + */ +quat.copy = vec4.copy; - context.initializeShader = function(name, attributes, uniforms) { - var shader = { - program: this.createProgram(), - fragment: this.getShader(name, this.FRAGMENT_SHADER), - vertex: this.getShader(name, this.VERTEX_SHADER), - attributes: [] - }; - this.attachShader(shader.program, shader.vertex); - this.attachShader(shader.program, shader.fragment); - this.linkProgram(shader.program); +/** + * Set the components of a quat to the given values + * + * @param {quat} out the receiving quaternion + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {quat} out + * @function + */ +quat.set = vec4.set; - if (!this.getProgramParameter(shader.program, this.LINK_STATUS)) { - console.error(this.getProgramInfoLog(shader.program)); - } else { - for (var i = 0; i < attributes.length; i++) { - shader[attributes[i]] = this.getAttribLocation(shader.program, attributes[i]); - shader.attributes.push(shader[attributes[i]]); - } - for (var k = 0; k < uniforms.length; k++) { - shader[uniforms[k]] = this.getUniformLocation(shader.program, uniforms[k]); - } - } +/** + * Set a quat to the identity quaternion + * + * @param {quat} out the receiving quaternion + * @returns {quat} out + */ +quat.identity = function(out) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +}; - return shader; - }; +/** + * Sets a quat from the given angle and rotation axis, + * then returns it. + * + * @param {quat} out the receiving quaternion + * @param {vec3} axis the axis around which to rotate + * @param {Number} rad the angle in radians + * @returns {quat} out + **/ +quat.setAxisAngle = function(out, axis, rad) { + rad = rad * 0.5; + var s = Math.sin(rad); + out[0] = s * axis[0]; + out[1] = s * axis[1]; + out[2] = s * axis[2]; + out[3] = Math.cos(rad); + return out; +}; - // Switches to a different shader program. - context.switchShader = function(shader, posMatrix, exMatrix) { - if (this.currentShader !== shader) { - this.useProgram(shader.program); +/** + * Gets the rotation axis and angle for a given + * quaternion. If a quaternion is created with + * setAxisAngle, this method will return the same + * values as providied in the original parameter list + * OR functionally equivalent values. + * Example: The quaternion formed by axis [0, 0, 1] and + * angle -90 is the same as the quaternion formed by + * [0, 0, 1] and 270. This method favors the latter. + * @param {vec3} out_axis Vector receiving the axis of rotation + * @param {quat} q Quaternion to be decomposed + * @return {Number} Angle, in radians, of the rotation + */ +quat.getAxisAngle = function(out_axis, q) { + var rad = Math.acos(q[3]) * 2.0; + var s = Math.sin(rad / 2.0); + if (s != 0.0) { + out_axis[0] = q[0] / s; + out_axis[1] = q[1] / s; + out_axis[2] = q[2] / s; + } else { + // If s is zero, return any axis (no rotation - axis does not matter) + out_axis[0] = 1; + out_axis[1] = 0; + out_axis[2] = 0; + } + return rad; +}; - // Disable all attributes from the existing shader that aren't used in - // the new shader. Note: attribute indices are *not* program specific! - var enabled = this.currentShader ? this.currentShader.attributes : []; - var required = shader.attributes; +/** + * Adds two quat's + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @returns {quat} out + * @function + */ +quat.add = vec4.add; - for (var i = 0; i < enabled.length; i++) { - if (required.indexOf(enabled[i]) < 0) { - this.disableVertexAttribArray(enabled[i]); - } - } +/** + * Multiplies two quat's + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @returns {quat} out + */ +quat.multiply = function(out, a, b) { + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + bx = b[0], by = b[1], bz = b[2], bw = b[3]; - // Enable all attributes for the new shader. - for (var j = 0; j < required.length; j++) { - if (enabled.indexOf(required[j]) < 0) { - this.enableVertexAttribArray(required[j]); - } - } + out[0] = ax * bw + aw * bx + ay * bz - az * by; + out[1] = ay * bw + aw * by + az * bx - ax * bz; + out[2] = az * bw + aw * bz + ax * by - ay * bx; + out[3] = aw * bw - ax * bx - ay * by - az * bz; + return out; +}; - this.currentShader = shader; - } +/** + * Alias for {@link quat.multiply} + * @function + */ +quat.mul = quat.multiply; - if (posMatrix !== undefined) context.setPosMatrix(posMatrix); - if (exMatrix !== undefined) context.setExMatrix(exMatrix); - }; +/** + * Scales a quat by a scalar number + * + * @param {quat} out the receiving vector + * @param {quat} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {quat} out + * @function + */ +quat.scale = vec4.scale; - // Update the matrices if necessary. Note: This relies on object identity! - // This means changing the matrix values without the actual matrix object - // will FAIL to update the matrix properly. - context.setPosMatrix = function(posMatrix) { - var shader = this.currentShader; - if (shader.posMatrix !== posMatrix) { - this.uniformMatrix4fv(shader.u_matrix, false, posMatrix); - shader.posMatrix = posMatrix; - } - }; +/** + * Rotates a quaternion by the given angle about the X axis + * + * @param {quat} out quat receiving operation result + * @param {quat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ +quat.rotateX = function (out, a, rad) { + rad *= 0.5; - // Update the matrices if necessary. Note: This relies on object identity! - // This means changing the matrix values without the actual matrix object - // will FAIL to update the matrix properly. - context.setExMatrix = function(exMatrix) { - var shader = this.currentShader; - if (exMatrix && shader.exMatrix !== exMatrix && shader.u_exmatrix) { - this.uniformMatrix4fv(shader.u_exmatrix, false, exMatrix); - shader.exMatrix = exMatrix; - } - }; + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + bx = Math.sin(rad), bw = Math.cos(rad); - context.vertexAttrib2fv = function(attribute, values) { - context.vertexAttrib2f(attribute, values[0], values[1]); - }; + out[0] = ax * bw + aw * bx; + out[1] = ay * bw + az * bx; + out[2] = az * bw - ay * bx; + out[3] = aw * bw - ax * bx; + return out; +}; - context.vertexAttrib3fv = function(attribute, values) { - context.vertexAttrib3f(attribute, values[0], values[1], values[2]); - }; +/** + * Rotates a quaternion by the given angle about the Y axis + * + * @param {quat} out quat receiving operation result + * @param {quat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ +quat.rotateY = function (out, a, rad) { + rad *= 0.5; - context.vertexAttrib4fv = function(attribute, values) { - context.vertexAttrib4f(attribute, values[0], values[1], values[2], values[3]); - }; + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + by = Math.sin(rad), bw = Math.cos(rad); - return context; + out[0] = ax * bw - az * by; + out[1] = ay * bw + aw * by; + out[2] = az * bw + ax * by; + out[3] = aw * bw - ay * by; + return out; }; -},{"../util/util":113,"./shaders":43}],41:[function(require,module,exports){ -'use strict'; - -module.exports = LineAtlas; - /** - * A LineAtlas lets us reuse rendered dashed lines - * by writing many of them to a texture and then fetching their positions - * using .getDash. + * Rotates a quaternion by the given angle about the Z axis * - * @param {number} width - * @param {number} height - * @private + * @param {quat} out quat receiving operation result + * @param {quat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out */ -function LineAtlas(width, height) { - this.width = width; - this.height = height; - this.nextRow = 0; - - this.bytes = 4; - this.data = new Uint8Array(this.width * this.height * this.bytes); +quat.rotateZ = function (out, a, rad) { + rad *= 0.5; - this.positions = {}; -} + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + bz = Math.sin(rad), bw = Math.cos(rad); -LineAtlas.prototype.setSprite = function(sprite) { - this.sprite = sprite; + out[0] = ax * bw + ay * bz; + out[1] = ay * bw - ax * bz; + out[2] = az * bw + aw * bz; + out[3] = aw * bw - az * bz; + return out; }; /** - * Get or create a dash line pattern. + * Calculates the W component of a quat from the X, Y, and Z components. + * Assumes that quaternion is 1 unit in length. + * Any existing W component will be ignored. * - * @param {Array} dasharray - * @param {boolean} round whether to add circle caps in between dash segments - * @returns {Object} position of dash texture in { y, height, width } - * @private + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate W component of + * @returns {quat} out */ -LineAtlas.prototype.getDash = function(dasharray, round) { - var key = dasharray.join(",") + round; +quat.calculateW = function (out, a) { + var x = a[0], y = a[1], z = a[2]; - if (!this.positions[key]) { - this.positions[key] = this.addDash(dasharray, round); - } - return this.positions[key]; + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); + return out; }; -LineAtlas.prototype.addDash = function(dasharray, round) { - - var n = round ? 7 : 0; - var height = 2 * n + 1; - var offset = 128; - - if (this.nextRow + height > this.height) { - console.warn('LineAtlas out of space'); - return null; - } - - var length = 0; - for (var i = 0; i < dasharray.length; i++) { - length += dasharray[i]; - } +/** + * Calculates the dot product of two quat's + * + * @param {quat} a the first operand + * @param {quat} b the second operand + * @returns {Number} dot product of a and b + * @function + */ +quat.dot = vec4.dot; - var stretch = this.width / length; - var halfWidth = stretch / 2; +/** + * Performs a linear interpolation between two quat's + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {quat} out + * @function + */ +quat.lerp = vec4.lerp; - // If dasharray has an odd length, both the first and last parts - // are dashes and should be joined seamlessly. - var oddLength = dasharray.length % 2 === 1; - - for (var y = -n; y <= n; y++) { - var row = this.nextRow + n + y; - var index = this.width * row; - - var left = oddLength ? -dasharray[dasharray.length - 1] : 0; - var right = dasharray[0]; - var partIndex = 1; - - for (var x = 0; x < this.width; x++) { - - while (right < x / stretch) { - left = right; - right = right + dasharray[partIndex]; - - if (oddLength && partIndex === dasharray.length - 1) { - right += dasharray[0]; - } - - partIndex++; - } - - var distLeft = Math.abs(x - left * stretch); - var distRight = Math.abs(x - right * stretch); - var dist = Math.min(distLeft, distRight); - var inside = (partIndex % 2) === 1; - var signedDistance; - - if (round) { - // Add circle caps - var distMiddle = n ? y / n * (halfWidth + 1) : 0; - if (inside) { - var distEdge = halfWidth - Math.abs(distMiddle); - signedDistance = Math.sqrt(dist * dist + distEdge * distEdge); - } else { - signedDistance = halfWidth - Math.sqrt(dist * dist + distMiddle * distMiddle); - } - } else { - signedDistance = (inside ? 1 : -1) * dist; - } - - this.data[3 + (index + x) * 4] = Math.max(0, Math.min(255, signedDistance + offset)); - } - } - - var pos = { - y: (this.nextRow + n + 0.5) / this.height, - height: 2 * n / this.height, - width: length - }; - - this.nextRow += height; - this.dirty = true; - - return pos; -}; +/** + * Performs a spherical linear interpolation between two quat + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {quat} out + */ +quat.slerp = function (out, a, b, t) { + // benchmarks: + // http://jsperf.com/quaternion-slerp-implementations -LineAtlas.prototype.bind = function(gl) { - if (!this.texture) { - this.texture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.data); + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + bx = b[0], by = b[1], bz = b[2], bw = b[3]; - } else { - gl.bindTexture(gl.TEXTURE_2D, this.texture); + var omega, cosom, sinom, scale0, scale1; - if (this.dirty) { - this.dirty = false; - gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, this.width, this.height, gl.RGBA, gl.UNSIGNED_BYTE, this.data); - } + // calc cosine + cosom = ax * bx + ay * by + az * bz + aw * bw; + // adjust signs (if necessary) + if ( cosom < 0.0 ) { + cosom = -cosom; + bx = - bx; + by = - by; + bz = - bz; + bw = - bw; } -}; - -LineAtlas.prototype.debug = function() { - - var canvas = document.createElement('canvas'); - - document.body.appendChild(canvas); - canvas.style.position = 'absolute'; - canvas.style.top = 0; - canvas.style.left = 0; - canvas.style.background = '#ff0'; - - canvas.width = this.width; - canvas.height = this.height; - - var ctx = canvas.getContext('2d'); - var data = ctx.getImageData(0, 0, this.width, this.height); - for (var i = 0; i < this.data.length; i++) { - if (this.sdf) { - var k = i * 4; - data.data[k] = data.data[k + 1] = data.data[k + 2] = 0; - data.data[k + 3] = this.data[i]; - } else { - data.data[i] = this.data[i]; - } + // calculate coefficients + if ( (1.0 - cosom) > 0.000001 ) { + // standard case (slerp) + omega = Math.acos(cosom); + sinom = Math.sin(omega); + scale0 = Math.sin((1.0 - t) * omega) / sinom; + scale1 = Math.sin(t * omega) / sinom; + } else { + // "from" and "to" quaternions are very close + // ... so we can do a linear interpolation + scale0 = 1.0 - t; + scale1 = t; } - ctx.putImageData(data, 0, 0); + // calculate final values + out[0] = scale0 * ax + scale1 * bx; + out[1] = scale0 * ay + scale1 * by; + out[2] = scale0 * az + scale1 * bz; + out[3] = scale0 * aw + scale1 * bw; + + return out; }; -},{}],42:[function(require,module,exports){ -'use strict'; - -var glutil = require('./gl_util'); -var browser = require('../util/browser'); -var mat4 = require('gl-matrix').mat4; -var FrameHistory = require('./frame_history'); -var TileCoord = require('../source/tile_coord'); -var EXTENT = require('../data/buffer').EXTENT; - -/* - * Initialize a new painter object. +/** + * Performs a spherical linear interpolation with two control points * - * @param {Canvas} gl an experimental-webgl drawing context + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @param {quat} c the third operand + * @param {quat} d the fourth operand + * @param {Number} t interpolation amount + * @returns {quat} out */ -module.exports = Painter; -function Painter(gl, transform) { - this.gl = glutil.extend(gl); - this.transform = transform; - - this.reusableTextures = {}; - this.preFbos = {}; - - this.frameHistory = new FrameHistory(); - - this.setup(); - - // Within each layer there are 3 distinct z-planes that can be drawn to. - // This is implemented using the WebGL depth buffer. - this.numSublayers = 3; - this.depthEpsilon = 1 / Math.pow(2, 16); -} +quat.sqlerp = (function () { + var temp1 = quat.create(); + var temp2 = quat.create(); + + return function (out, a, b, c, d, t) { + quat.slerp(temp1, a, d, t); + quat.slerp(temp2, b, c, t); + quat.slerp(out, temp1, temp2, 2 * t * (1 - t)); + + return out; + }; +}()); -/* - * Update the GL viewport, projection matrix, and transforms to compensate - * for a new width and height value. +/** + * Calculates the inverse of a quat + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate inverse of + * @returns {quat} out */ -Painter.prototype.resize = function(width, height) { - var gl = this.gl; +quat.invert = function(out, a) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], + dot = a0*a0 + a1*a1 + a2*a2 + a3*a3, + invDot = dot ? 1.0/dot : 0; + + // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 - this.width = width * browser.devicePixelRatio; - this.height = height * browser.devicePixelRatio; - gl.viewport(0, 0, this.width, this.height); + out[0] = -a0*invDot; + out[1] = -a1*invDot; + out[2] = -a2*invDot; + out[3] = a3*invDot; + return out; +}; +/** + * Calculates the conjugate of a quat + * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result. + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate conjugate of + * @returns {quat} out + */ +quat.conjugate = function (out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = a[3]; + return out; }; +/** + * Calculates the length of a quat + * + * @param {quat} a vector to calculate length of + * @returns {Number} length of a + * @function + */ +quat.length = vec4.length; -Painter.prototype.setup = function() { - var gl = this.gl; +/** + * Alias for {@link quat.length} + * @function + */ +quat.len = quat.length; - gl.verbose = true; +/** + * Calculates the squared length of a quat + * + * @param {quat} a vector to calculate squared length of + * @returns {Number} squared length of a + * @function + */ +quat.squaredLength = vec4.squaredLength; - // We are blending the new pixels *behind* the existing pixels. That way we can - // draw front-to-back and use then stencil buffer to cull opaque pixels early. - gl.enable(gl.BLEND); - gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); +/** + * Alias for {@link quat.squaredLength} + * @function + */ +quat.sqrLen = quat.squaredLength; - gl.enable(gl.STENCIL_TEST); +/** + * Normalize a quat + * + * @param {quat} out the receiving quaternion + * @param {quat} a quaternion to normalize + * @returns {quat} out + * @function + */ +quat.normalize = vec4.normalize; - gl.enable(gl.DEPTH_TEST); - gl.depthFunc(gl.LEQUAL); +/** + * Creates a quaternion from the given 3x3 rotation matrix. + * + * NOTE: The resultant quaternion is not normalized, so you should be sure + * to renormalize the quaternion yourself where necessary. + * + * @param {quat} out the receiving quaternion + * @param {mat3} m rotation matrix + * @returns {quat} out + * @function + */ +quat.fromMat3 = function(out, m) { + // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes + // article "Quaternion Calculus and Fast Animation". + var fTrace = m[0] + m[4] + m[8]; + var fRoot; - this._depthMask = false; - gl.depthMask(false); - - // Initialize shaders - this.debugShader = gl.initializeShader('debug', - ['a_pos'], - ['u_matrix', 'u_color']); - - this.rasterShader = gl.initializeShader('raster', - ['a_pos', 'a_texture_pos'], - ['u_matrix', 'u_brightness_low', 'u_brightness_high', 'u_saturation_factor', 'u_spin_weights', 'u_contrast_factor', 'u_opacity0', 'u_opacity1', 'u_image0', 'u_image1', 'u_tl_parent', 'u_scale_parent', 'u_buffer_scale']); - - this.circleShader = gl.initializeShader('circle', - ['a_pos'], - ['u_matrix', 'u_exmatrix', 'u_blur', 'u_size', 'u_color']); + if ( fTrace > 0.0 ) { + // |w| > 1/2, may as well choose w > 1/2 + fRoot = Math.sqrt(fTrace + 1.0); // 2w + out[3] = 0.5 * fRoot; + fRoot = 0.5/fRoot; // 1/(4w) + out[0] = (m[5]-m[7])*fRoot; + out[1] = (m[6]-m[2])*fRoot; + out[2] = (m[1]-m[3])*fRoot; + } else { + // |w| <= 1/2 + var i = 0; + if ( m[4] > m[0] ) + i = 1; + if ( m[8] > m[i*3+i] ) + i = 2; + var j = (i+1)%3; + var k = (i+2)%3; + + fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0); + out[i] = 0.5 * fRoot; + fRoot = 0.5 / fRoot; + out[3] = (m[j*3+k] - m[k*3+j]) * fRoot; + out[j] = (m[j*3+i] + m[i*3+j]) * fRoot; + out[k] = (m[k*3+i] + m[i*3+k]) * fRoot; + } + + return out; +}; - this.lineShader = gl.initializeShader('line', - ['a_pos', 'a_data'], - ['u_matrix', 'u_linewidth', 'u_color', 'u_ratio', 'u_blur', 'u_extra', 'u_antialiasingmatrix', 'u_offset', 'u_exmatrix']); +/** + * Returns a string representation of a quatenion + * + * @param {quat} vec vector to represent as a string + * @returns {String} string representation of the vector + */ +quat.str = function (a) { + return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; +}; - this.linepatternShader = gl.initializeShader('linepattern', - ['a_pos', 'a_data'], - ['u_matrix', 'u_linewidth', 'u_ratio', 'u_pattern_size_a', 'u_pattern_size_b', 'u_pattern_tl_a', 'u_pattern_br_a', 'u_pattern_tl_b', 'u_pattern_br_b', 'u_blur', 'u_fade', 'u_opacity', 'u_extra', 'u_antialiasingmatrix', 'u_offset']); +/** + * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===) + * + * @param {quat} a The first quaternion. + * @param {quat} b The second quaternion. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ +quat.exactEquals = vec4.exactEquals; - this.linesdfpatternShader = gl.initializeShader('linesdfpattern', - ['a_pos', 'a_data'], - ['u_matrix', 'u_linewidth', 'u_color', 'u_ratio', 'u_blur', 'u_patternscale_a', 'u_tex_y_a', 'u_patternscale_b', 'u_tex_y_b', 'u_image', 'u_sdfgamma', 'u_mix', 'u_extra', 'u_antialiasingmatrix', 'u_offset']); +/** + * Returns whether or not the quaternions have approximately the same elements in the same position. + * + * @param {quat} a The first vector. + * @param {quat} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ +quat.equals = vec4.equals; - this.dotShader = gl.initializeShader('dot', - ['a_pos'], - ['u_matrix', 'u_size', 'u_color', 'u_blur']); +module.exports = quat; - this.sdfShader = gl.initializeShader('sdf', - ['a_pos', 'a_offset', 'a_data1', 'a_data2'], - ['u_matrix', 'u_exmatrix', 'u_texture', 'u_texsize', 'u_color', 'u_gamma', 'u_buffer', 'u_zoom', 'u_fadedist', 'u_minfadezoom', 'u_maxfadezoom', 'u_fadezoom', 'u_skewed', 'u_extra']); +},{"./common.js":30,"./mat3.js":33,"./vec3.js":37,"./vec4.js":38}],36:[function(require,module,exports){ +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - this.iconShader = gl.initializeShader('icon', - ['a_pos', 'a_offset', 'a_data1', 'a_data2'], - ['u_matrix', 'u_exmatrix', 'u_texture', 'u_texsize', 'u_zoom', 'u_fadedist', 'u_minfadezoom', 'u_maxfadezoom', 'u_fadezoom', 'u_opacity', 'u_skewed', 'u_extra']); +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: - this.outlineShader = gl.initializeShader('outline', - ['a_pos'], - ['u_matrix', 'u_color', 'u_world'] - ); +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - this.patternShader = gl.initializeShader('pattern', - ['a_pos'], - ['u_matrix', 'u_pattern_tl_a', 'u_pattern_br_a', 'u_pattern_tl_b', 'u_pattern_br_b', 'u_mix', 'u_patternscale_a', 'u_patternscale_b', 'u_opacity', 'u_image', 'u_offset_a', 'u_offset_b'] - ); +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. */ - this.fillShader = gl.initializeShader('fill', - ['a_pos'], - ['u_matrix', 'u_color'] - ); +var glMatrix = require("./common.js"); - this.collisionBoxShader = gl.initializeShader('collisionbox', - ['a_pos', 'a_extrude', 'a_data'], - ['u_matrix', 'u_scale', 'u_zoom', 'u_maxzoom'] - ); +/** + * @class 2 Dimensional Vector + * @name vec2 + */ +var vec2 = {}; - this.identityMatrix = mat4.create(); - - // The backgroundBuffer is used when drawing to the full *canvas* - this.backgroundBuffer = gl.createBuffer(); - this.backgroundBuffer.itemSize = 2; - this.backgroundBuffer.itemCount = 4; - gl.bindBuffer(gl.ARRAY_BUFFER, this.backgroundBuffer); - gl.bufferData(gl.ARRAY_BUFFER, new Int16Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW); - - // The tileExtentBuffer is used when drawing to a full *tile* - this.tileExtentBuffer = gl.createBuffer(); - this.tileExtentBuffer.itemSize = 4; - this.tileExtentBuffer.itemCount = 4; - gl.bindBuffer(gl.ARRAY_BUFFER, this.tileExtentBuffer); - gl.bufferData( - gl.ARRAY_BUFFER, - new Int16Array([ - // tile coord x, tile coord y, texture coord x, texture coord y - 0, 0, 0, 0, - EXTENT, 0, 32767, 0, - 0, EXTENT, 0, 32767, - EXTENT, EXTENT, 32767, 32767 - ]), - gl.STATIC_DRAW); +/** + * Creates a new, empty vec2 + * + * @returns {vec2} a new 2D vector + */ +vec2.create = function() { + var out = new glMatrix.ARRAY_TYPE(2); + out[0] = 0; + out[1] = 0; + return out; +}; - // The debugBuffer is used to draw tile outlines for debugging - this.debugBuffer = gl.createBuffer(); - this.debugBuffer.itemSize = 2; - this.debugBuffer.itemCount = 5; - gl.bindBuffer(gl.ARRAY_BUFFER, this.debugBuffer); - gl.bufferData( - gl.ARRAY_BUFFER, - new Int16Array([ - 0, 0, EXTENT, 0, EXTENT, EXTENT, 0, EXTENT, 0, 0]), - gl.STATIC_DRAW); +/** + * Creates a new vec2 initialized with values from an existing vector + * + * @param {vec2} a vector to clone + * @returns {vec2} a new 2D vector + */ +vec2.clone = function(a) { + var out = new glMatrix.ARRAY_TYPE(2); + out[0] = a[0]; + out[1] = a[1]; + return out; +}; - // The debugTextBuffer is used to draw tile IDs for debugging - this.debugTextBuffer = gl.createBuffer(); - this.debugTextBuffer.itemSize = 2; +/** + * Creates a new vec2 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @returns {vec2} a new 2D vector + */ +vec2.fromValues = function(x, y) { + var out = new glMatrix.ARRAY_TYPE(2); + out[0] = x; + out[1] = y; + return out; }; -/* - * Reset the color buffers of the drawing canvas. +/** + * Copy the values from one vec2 to another + * + * @param {vec2} out the receiving vector + * @param {vec2} a the source vector + * @returns {vec2} out */ -Painter.prototype.clearColor = function() { - var gl = this.gl; - gl.clearColor(0, 0, 0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); +vec2.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + return out; }; -/* - * Reset the drawing canvas by clearing the stencil buffer so that we can draw - * new tiles at the same location, while retaining previously drawn pixels. +/** + * Set the components of a vec2 to the given values + * + * @param {vec2} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @returns {vec2} out */ -Painter.prototype.clearStencil = function() { - var gl = this.gl; - gl.clearStencil(0x0); - gl.stencilMask(0xFF); - gl.clear(gl.STENCIL_BUFFER_BIT); +vec2.set = function(out, x, y) { + out[0] = x; + out[1] = y; + return out; }; -Painter.prototype.clearDepth = function() { - var gl = this.gl; - gl.clearDepth(1); - this.depthMask(true); - gl.clear(gl.DEPTH_BUFFER_BIT); +/** + * Adds two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.add = function(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + return out; }; -Painter.prototype._renderTileClippingMasks = function(coords, sourceMaxZoom) { - var gl = this.gl; - gl.colorMask(false, false, false, false); - this.depthMask(false); - gl.disable(gl.DEPTH_TEST); - gl.enable(gl.STENCIL_TEST); +/** + * Subtracts vector b from vector a + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.subtract = function(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + return out; +}; - // Only write clipping IDs to the last 5 bits. The first three are used for drawing fills. - gl.stencilMask(0xF8); - // Tests will always pass, and ref value will be written to stencil buffer. - gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE); +/** + * Alias for {@link vec2.subtract} + * @function + */ +vec2.sub = vec2.subtract; - var idNext = 1; - this._tileClippingMaskIDs = {}; - for (var i = 0; i < coords.length; i++) { - var coord = coords[i]; - var id = this._tileClippingMaskIDs[coord.id] = (idNext++) << 3; +/** + * Multiplies two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.multiply = function(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + return out; +}; - gl.stencilFunc(gl.ALWAYS, id, 0xF8); +/** + * Alias for {@link vec2.multiply} + * @function + */ +vec2.mul = vec2.multiply; - gl.switchShader(this.fillShader, this.calculatePosMatrix(coord, sourceMaxZoom)); +/** + * Divides two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.divide = function(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + return out; +}; - // Draw the clipping mask - gl.bindBuffer(gl.ARRAY_BUFFER, this.tileExtentBuffer); - gl.vertexAttribPointer(this.fillShader.a_pos, this.tileExtentBuffer.itemSize, gl.SHORT, false, 8, 0); - gl.drawArrays(gl.TRIANGLE_STRIP, 0, this.tileExtentBuffer.itemCount); - } +/** + * Alias for {@link vec2.divide} + * @function + */ +vec2.div = vec2.divide; - gl.stencilMask(0x00); - gl.colorMask(true, true, true, true); - this.depthMask(true); - gl.enable(gl.DEPTH_TEST); +/** + * Math.ceil the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to ceil + * @returns {vec2} out + */ +vec2.ceil = function (out, a) { + out[0] = Math.ceil(a[0]); + out[1] = Math.ceil(a[1]); + return out; }; -Painter.prototype.enableTileClippingMask = function(coord) { - var gl = this.gl; - gl.stencilFunc(gl.EQUAL, this._tileClippingMaskIDs[coord.id], 0xF8); +/** + * Math.floor the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to floor + * @returns {vec2} out + */ +vec2.floor = function (out, a) { + out[0] = Math.floor(a[0]); + out[1] = Math.floor(a[1]); + return out; }; -// Overridden by headless tests. -Painter.prototype.prepareBuffers = function() {}; -Painter.prototype.bindDefaultFramebuffer = function() { - var gl = this.gl; - gl.bindFramebuffer(gl.FRAMEBUFFER, null); +/** + * Returns the minimum of two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.min = function(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + return out; }; -var draw = { - symbol: require('./draw_symbol'), - circle: require('./draw_circle'), - line: require('./draw_line'), - fill: require('./draw_fill'), - raster: require('./draw_raster'), - background: require('./draw_background'), - debug: require('./draw_debug') +/** + * Returns the maximum of two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.max = function(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + return out; }; -Painter.prototype.render = function(style, options) { - this.style = style; - this.options = options; - - this.lineAtlas = style.lineAtlas; - - this.spriteAtlas = style.spriteAtlas; - this.spriteAtlas.setSprite(style.sprite); - - this.glyphSource = style.glyphSource; - - this.frameHistory.record(this.transform.zoom); - - this.prepareBuffers(); - this.clearColor(); - this.clearDepth(); - - this.depthRange = (style._order.length + 2) * this.numSublayers * this.depthEpsilon; - - this.renderPass({isOpaquePass: true}); - this.renderPass({isOpaquePass: false}); +/** + * Math.round the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to round + * @returns {vec2} out + */ +vec2.round = function (out, a) { + out[0] = Math.round(a[0]); + out[1] = Math.round(a[1]); + return out; }; -Painter.prototype.renderPass = function(options) { - var groups = this.style._groups; - var isOpaquePass = options.isOpaquePass; - this.currentLayer = isOpaquePass ? this.style._order.length : -1; - - for (var i = 0; i < groups.length; i++) { - var group = groups[isOpaquePass ? groups.length - 1 - i : i]; - var source = this.style.sources[group.source]; - - var coords = []; - if (source) { - coords = source.getVisibleCoordinates(); - this.clearStencil(); - if (source.prepare) source.prepare(); - if (source.isTileClipped) { - this._renderTileClippingMasks(coords, source.maxzoom); - } - } - - if (isOpaquePass) { - this.gl.disable(this.gl.BLEND); - this.isOpaquePass = true; - } else { - this.gl.enable(this.gl.BLEND); - this.isOpaquePass = false; - coords.reverse(); - } - - for (var j = 0; j < group.length; j++) { - var layer = group[isOpaquePass ? group.length - 1 - j : j]; - this.currentLayer += isOpaquePass ? -1 : 1; - this.renderLayer(this, source, layer, coords); - } - - if (source) { - draw.debug(this, source, coords); - } - } +/** + * Scales a vec2 by a scalar number + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec2} out + */ +vec2.scale = function(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + return out; }; -Painter.prototype.depthMask = function(mask) { - if (mask !== this._depthMask) { - this._depthMask = mask; - this.gl.depthMask(mask); - } +/** + * Adds two vec2's after scaling the second operand by a scalar value + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec2} out + */ +vec2.scaleAndAdd = function(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + return out; }; -Painter.prototype.renderLayer = function(painter, source, layer, coords) { - if (layer.isHidden(this.transform.zoom)) return; - if (layer.type !== 'background' && !coords.length) return; - draw[layer.type](painter, source, layer, coords); +/** + * Calculates the euclidian distance between two vec2's + * + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {Number} distance between a and b + */ +vec2.distance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1]; + return Math.sqrt(x*x + y*y); }; -// Draws non-opaque areas. This is for debugging purposes. -Painter.prototype.drawStencilBuffer = function() { - var gl = this.gl; - gl.switchShader(this.fillShader, this.identityMatrix); - - gl.stencilMask(0x00); - gl.stencilFunc(gl.EQUAL, 0x80, 0x80); - - // Drw the filling quad where the stencil buffer isn't set. - gl.bindBuffer(gl.ARRAY_BUFFER, this.backgroundBuffer); - gl.vertexAttribPointer(this.fillShader.a_pos, this.backgroundBuffer.itemSize, gl.SHORT, false, 0, 0); - - gl.uniform4fv(this.fillShader.u_color, [0, 0, 0, 0.5]); - gl.drawArrays(gl.TRIANGLE_STRIP, 0, this.tileExtentBuffer.itemCount); -}; +/** + * Alias for {@link vec2.distance} + * @function + */ +vec2.dist = vec2.distance; -Painter.prototype.setDepthSublayer = function(n) { - var farDepth = 1 - ((1 + this.currentLayer) * this.numSublayers + n) * this.depthEpsilon; - var nearDepth = farDepth - 1 + this.depthRange; - this.gl.depthRange(nearDepth, farDepth); +/** + * Calculates the squared euclidian distance between two vec2's + * + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {Number} squared distance between a and b + */ +vec2.squaredDistance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1]; + return x*x + y*y; }; -Painter.prototype.translatePosMatrix = function(matrix, tile, translate, anchor) { - if (!translate[0] && !translate[1]) return matrix; - - if (anchor === 'viewport') { - var sinA = Math.sin(-this.transform.angle); - var cosA = Math.cos(-this.transform.angle); - translate = [ - translate[0] * cosA - translate[1] * sinA, - translate[0] * sinA + translate[1] * cosA - ]; - } - - var translation = [ - tile.pixelsToTileUnits(translate[0], this.transform.zoom), - tile.pixelsToTileUnits(translate[1], this.transform.zoom), - 0 - ]; +/** + * Alias for {@link vec2.squaredDistance} + * @function + */ +vec2.sqrDist = vec2.squaredDistance; - var translatedMatrix = new Float32Array(16); - mat4.translate(translatedMatrix, matrix, translation); - return translatedMatrix; +/** + * Calculates the length of a vec2 + * + * @param {vec2} a vector to calculate length of + * @returns {Number} length of a + */ +vec2.length = function (a) { + var x = a[0], + y = a[1]; + return Math.sqrt(x*x + y*y); }; /** - * Calculate the posMatrix that this tile uses to display itself in a map, - * given a coordinate as (z, x, y) and a transform - * @param {Object} transform - * @private + * Alias for {@link vec2.length} + * @function */ -Painter.prototype.calculatePosMatrix = function(coord, maxZoom) { - - if (coord instanceof TileCoord) { - coord = coord.toCoordinate(); - } - var transform = this.transform; - - if (maxZoom === undefined) maxZoom = Infinity; - - // Initialize model-view matrix that converts from the tile coordinates - // to screen coordinates. - - // if z > maxzoom then the tile is actually a overscaled maxzoom tile, - // so calculate the matrix the maxzoom tile would use. - var z = Math.min(coord.zoom, maxZoom); - var x = coord.column; - var y = coord.row; +vec2.len = vec2.length; - var scale = transform.worldSize / Math.pow(2, z); +/** + * Calculates the squared length of a vec2 + * + * @param {vec2} a vector to calculate squared length of + * @returns {Number} squared length of a + */ +vec2.squaredLength = function (a) { + var x = a[0], + y = a[1]; + return x*x + y*y; +}; - // The position matrix - var posMatrix = new Float64Array(16); +/** + * Alias for {@link vec2.squaredLength} + * @function + */ +vec2.sqrLen = vec2.squaredLength; - mat4.identity(posMatrix); - mat4.translate(posMatrix, posMatrix, [x * scale, y * scale, 0]); - mat4.scale(posMatrix, posMatrix, [ scale / EXTENT, scale / EXTENT, 1 ]); - mat4.multiply(posMatrix, transform.projMatrix, posMatrix); +/** + * Negates the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to negate + * @returns {vec2} out + */ +vec2.negate = function(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + return out; +}; - return new Float32Array(posMatrix); +/** + * Returns the inverse of the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to invert + * @returns {vec2} out + */ +vec2.inverse = function(out, a) { + out[0] = 1.0 / a[0]; + out[1] = 1.0 / a[1]; + return out; }; -Painter.prototype.saveTexture = function(texture) { - var textures = this.reusableTextures[texture.size]; - if (!textures) { - this.reusableTextures[texture.size] = [texture]; - } else { - textures.push(texture); +/** + * Normalize a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to normalize + * @returns {vec2} out + */ +vec2.normalize = function(out, a) { + var x = a[0], + y = a[1]; + var len = x*x + y*y; + if (len > 0) { + //TODO: evaluate use of glm_invsqrt here? + len = 1 / Math.sqrt(len); + out[0] = a[0] * len; + out[1] = a[1] * len; } + return out; }; - -Painter.prototype.getTexture = function(size) { - var textures = this.reusableTextures[size]; - return textures && textures.length > 0 ? textures.pop() : null; +/** + * Calculates the dot product of two vec2's + * + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {Number} dot product of a and b + */ +vec2.dot = function (a, b) { + return a[0] * b[0] + a[1] * b[1]; }; -},{"../data/buffer":17,"../source/tile_coord":50,"../util/browser":102,"./draw_background":31,"./draw_circle":32,"./draw_debug":34,"./draw_fill":35,"./draw_line":36,"./draw_raster":37,"./draw_symbol":38,"./frame_history":39,"./gl_util":40,"gl-matrix":123}],43:[function(require,module,exports){ -'use strict'; +/** + * Computes the cross product of two vec2's + * Note that the cross product must by definition produce a 3D vector + * + * @param {vec3} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec3} out + */ +vec2.cross = function(out, a, b) { + var z = a[0] * b[1] - a[1] * b[0]; + out[0] = out[1] = 0; + out[2] = z; + return out; +}; - -var path = require('path'); - -// Must be written out long-form for brfs. -module.exports = { - debug: { - fragment: "precision mediump float;\n\nuniform vec4 u_color;\n\nvoid main() {\n gl_FragColor = u_color;\n}\n", - vertex: "precision mediump float;\n\nattribute vec2 a_pos;\n\nuniform highp mat4 u_matrix;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, step(32767.0, a_pos.x), 1);\n}\n" - }, - dot: { - fragment: "precision mediump float;\n\nuniform vec4 u_color;\nuniform float u_blur;\n\nvoid main() {\n float dist = length(gl_PointCoord - 0.5);\n float t = smoothstep(0.5, 0.5 - u_blur, dist);\n\n gl_FragColor = u_color * t;\n}\n", - vertex: "precision mediump float;\n\nuniform highp mat4 u_matrix;\nuniform float u_size;\n\nattribute vec2 a_pos;\n\nvoid main(void) {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n gl_PointSize = u_size;\n}\n" - }, - fill: { - fragment: "precision mediump float;\n\nuniform vec4 u_color;\n\nvoid main() {\n gl_FragColor = u_color;\n}\n", - vertex: "precision mediump float;\n\nattribute vec2 a_pos;\nuniform highp mat4 u_matrix;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n}\n" - }, - circle: { - fragment: "precision mediump float;\n\nuniform vec4 u_color;\nuniform float u_blur;\nuniform float u_size;\n\nvarying vec2 v_extrude;\n\nvoid main() {\n float t = smoothstep(1.0 - u_blur, 1.0, length(v_extrude));\n gl_FragColor = u_color * (1.0 - t);\n}\n", - vertex: "precision mediump float;\n\n// set by gl_util\nuniform float u_size;\n\nattribute vec2 a_pos;\n\nuniform highp mat4 u_matrix;\nuniform mat4 u_exmatrix;\n\nvarying vec2 v_extrude;\n\nvoid main(void) {\n // unencode the extrusion vector that we snuck into the a_pos vector\n v_extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0);\n\n vec4 extrude = u_exmatrix * vec4(v_extrude * u_size, 0, 0);\n // multiply a_pos by 0.5, since we had it * 2 in order to sneak\n // in extrusion data\n gl_Position = u_matrix * vec4(floor(a_pos * 0.5), 0, 1);\n\n // gl_Position is divided by gl_Position.w after this shader runs.\n // Multiply the extrude by it so that it isn't affected by it.\n gl_Position += extrude * gl_Position.w;\n}\n" - }, - line: { - fragment: "precision mediump float;\n\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\nuniform float u_blur;\n\nvarying vec2 v_normal;\nvarying float v_linesofar;\nvarying float v_gamma_scale;\n\nvoid main() {\n // Calculate the distance of the pixel from the line in pixels.\n float dist = length(v_normal) * u_linewidth.s;\n\n // Calculate the antialiasing fade factor. This is either when fading in\n // the line in case of an offset line (v_linewidth.t) or when fading out\n // (v_linewidth.s)\n float blur = u_blur * v_gamma_scale;\n float alpha = clamp(min(dist - (u_linewidth.t - blur), u_linewidth.s - dist) / blur, 0.0, 1.0);\n\n gl_FragColor = u_color * alpha;\n}\n", - vertex: "precision mediump float;\n\n// floor(127 / 2) == 63.0\n// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is\n// stored in a byte (-128..127). we scale regular normals up to length 63, but\n// there are also \"special\" normals that have a bigger length (of up to 126 in\n// this case).\n// #define scale 63.0\n#define scale 0.015873016\n\nattribute vec2 a_pos;\nattribute vec4 a_data;\n\nuniform highp mat4 u_matrix;\nuniform float u_ratio;\nuniform vec2 u_linewidth;\nuniform float u_extra;\nuniform mat2 u_antialiasingmatrix;\nuniform float u_offset;\n\nvarying vec2 v_normal;\nvarying float v_linesofar;\nvarying float v_gamma_scale;\n\nvoid main() {\n vec2 a_extrude = a_data.xy;\n float a_direction = sign(a_data.z) * mod(a_data.z, 2.0);\n\n // We store the texture normals in the most insignificant bit\n // transform y so that 0 => -1 and 1 => 1\n // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap\n // y is 1 if the normal points up, and -1 if it points down\n vec2 normal = mod(a_pos, 2.0);\n normal.y = sign(normal.y - 0.5);\n v_normal = normal;\n\n // Scale the extrusion vector down to a normal and then up by the line width\n // of this vertex.\n vec4 dist = vec4(u_linewidth.s * a_extrude * scale, 0.0, 0.0);\n\n // Calculate the offset when drawing a line that is to the side of the actual line.\n // We do this by creating a vector that points towards the extrude, but rotate\n // it when we're drawing round end points (a_direction = -1 or 1) since their\n // extrude vector points in another direction.\n float u = 0.5 * a_direction;\n float t = 1.0 - abs(u);\n vec2 offset = u_offset * a_extrude * scale * normal.y * mat2(t, -u, u, t);\n\n // Remove the texture normal bit of the position before scaling it with the\n // model/view matrix.\n gl_Position = u_matrix * vec4(floor(a_pos * 0.5) + (offset + dist.xy) / u_ratio, 0.0, 1.0);\n\n // position of y on the screen\n float y = gl_Position.y / gl_Position.w;\n\n // how much features are squished in the y direction by the tilt\n float squish_scale = length(a_extrude) / length(u_antialiasingmatrix * a_extrude);\n\n // how much features are squished in all directions by the perspectiveness\n float perspective_scale = 1.0 / (1.0 - min(y * u_extra, 0.9));\n\n v_gamma_scale = perspective_scale * squish_scale;\n}\n" - }, - linepattern: { - fragment: "precision mediump float;\n\nuniform vec2 u_linewidth;\nuniform float u_point;\nuniform float u_blur;\n\nuniform vec2 u_pattern_size_a;\nuniform vec2 u_pattern_size_b;\nuniform vec2 u_pattern_tl_a;\nuniform vec2 u_pattern_br_a;\nuniform vec2 u_pattern_tl_b;\nuniform vec2 u_pattern_br_b;\nuniform float u_fade;\nuniform float u_opacity;\n\nuniform sampler2D u_image;\n\nvarying vec2 v_normal;\nvarying float v_linesofar;\nvarying float v_gamma_scale;\n\nvoid main() {\n // Calculate the distance of the pixel from the line in pixels.\n float dist = length(v_normal) * u_linewidth.s;\n\n // Calculate the antialiasing fade factor. This is either when fading in\n // the line in case of an offset line (v_linewidth.t) or when fading out\n // (v_linewidth.s)\n float blur = u_blur * v_gamma_scale;\n float alpha = clamp(min(dist - (u_linewidth.t - blur), u_linewidth.s - dist) / blur, 0.0, 1.0);\n\n float x_a = mod(v_linesofar / u_pattern_size_a.x, 1.0);\n float x_b = mod(v_linesofar / u_pattern_size_b.x, 1.0);\n float y_a = 0.5 + (v_normal.y * u_linewidth.s / u_pattern_size_a.y);\n float y_b = 0.5 + (v_normal.y * u_linewidth.s / u_pattern_size_b.y);\n vec2 pos = mix(u_pattern_tl_a, u_pattern_br_a, vec2(x_a, y_a));\n vec2 pos2 = mix(u_pattern_tl_b, u_pattern_br_b, vec2(x_b, y_b));\n\n vec4 color = mix(texture2D(u_image, pos), texture2D(u_image, pos2), u_fade);\n\n alpha *= u_opacity;\n\n gl_FragColor = color * alpha;\n}\n", - vertex: "precision mediump float;\n\n// floor(127 / 2) == 63.0\n// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is\n// stored in a byte (-128..127). we scale regular normals up to length 63, but\n// there are also \"special\" normals that have a bigger length (of up to 126 in\n// this case).\n// #define scale 63.0\n#define scale 0.015873016\n\nattribute vec2 a_pos;\nattribute vec4 a_data;\n\nuniform highp mat4 u_matrix;\nuniform float u_ratio;\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\nuniform float u_extra;\nuniform mat2 u_antialiasingmatrix;\nuniform float u_offset;\n\nvarying vec2 v_normal;\nvarying float v_linesofar;\nvarying float v_gamma_scale;\n\nvoid main() {\n vec2 a_extrude = a_data.xy;\n float a_direction = sign(a_data.z) * mod(a_data.z, 2.0);\n float a_linesofar = abs(floor(a_data.z / 2.0)) + a_data.w * 64.0;\n\n // We store the texture normals in the most insignificant bit\n // transform y so that 0 => -1 and 1 => 1\n // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap\n // y is 1 if the normal points up, and -1 if it points down\n vec2 normal = mod(a_pos, 2.0);\n normal.y = sign(normal.y - 0.5);\n v_normal = normal;\n\n // Scale the extrusion vector down to a normal and then up by the line width\n // of this vertex.\n vec2 extrude = a_extrude * scale;\n vec2 dist = u_linewidth.s * extrude;\n\n // Calculate the offset when drawing a line that is to the side of the actual line.\n // We do this by creating a vector that points towards the extrude, but rotate\n // it when we're drawing round end points (a_direction = -1 or 1) since their\n // extrude vector points in another direction.\n float u = 0.5 * a_direction;\n float t = 1.0 - abs(u);\n vec2 offset = u_offset * a_extrude * scale * normal.y * mat2(t, -u, u, t);\n\n // Remove the texture normal bit of the position before scaling it with the\n // model/view matrix.\n gl_Position = u_matrix * vec4(floor(a_pos * 0.5) + (offset + dist.xy) / u_ratio, 0.0, 1.0);\n v_linesofar = a_linesofar;\n\n // position of y on the screen\n float y = gl_Position.y / gl_Position.w;\n\n // how much features are squished in the y direction by the tilt\n float squish_scale = length(a_extrude) / length(u_antialiasingmatrix * a_extrude);\n\n // how much features are squished in all directions by the perspectiveness\n float perspective_scale = 1.0 / (1.0 - min(y * u_extra, 0.9));\n\n v_gamma_scale = perspective_scale * squish_scale;\n}\n" - }, - linesdfpattern: { - fragment: "precision mediump float;\n\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\nuniform float u_blur;\nuniform sampler2D u_image;\nuniform float u_sdfgamma;\nuniform float u_mix;\n\nvarying vec2 v_normal;\nvarying vec2 v_tex_a;\nvarying vec2 v_tex_b;\nvarying float v_gamma_scale;\n\nvoid main() {\n // Calculate the distance of the pixel from the line in pixels.\n float dist = length(v_normal) * u_linewidth.s;\n\n // Calculate the antialiasing fade factor. This is either when fading in\n // the line in case of an offset line (v_linewidth.t) or when fading out\n // (v_linewidth.s)\n float blur = u_blur * v_gamma_scale;\n float alpha = clamp(min(dist - (u_linewidth.t - blur), u_linewidth.s - dist) / blur, 0.0, 1.0);\n\n float sdfdist_a = texture2D(u_image, v_tex_a).a;\n float sdfdist_b = texture2D(u_image, v_tex_b).a;\n float sdfdist = mix(sdfdist_a, sdfdist_b, u_mix);\n alpha *= smoothstep(0.5 - u_sdfgamma, 0.5 + u_sdfgamma, sdfdist);\n\n gl_FragColor = u_color * alpha;\n}\n", - vertex: "precision mediump float;\n\n// floor(127 / 2) == 63.0\n// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is\n// stored in a byte (-128..127). we scale regular normals up to length 63, but\n// there are also \"special\" normals that have a bigger length (of up to 126 in\n// this case).\n// #define scale 63.0\n#define scale 0.015873016\n\nattribute vec2 a_pos;\nattribute vec4 a_data;\n\nuniform highp mat4 u_matrix;\nuniform vec2 u_linewidth;\nuniform float u_ratio;\nuniform vec2 u_patternscale_a;\nuniform float u_tex_y_a;\nuniform vec2 u_patternscale_b;\nuniform float u_tex_y_b;\nuniform float u_extra;\nuniform mat2 u_antialiasingmatrix;\nuniform float u_offset;\n\nvarying vec2 v_normal;\nvarying vec2 v_tex_a;\nvarying vec2 v_tex_b;\nvarying float v_gamma_scale;\n\nvoid main() {\n vec2 a_extrude = a_data.xy;\n float a_direction = sign(a_data.z) * mod(a_data.z, 2.0);\n float a_linesofar = abs(floor(a_data.z / 2.0)) + a_data.w * 64.0;\n\n // We store the texture normals in the most insignificant bit\n // transform y so that 0 => -1 and 1 => 1\n // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap\n // y is 1 if the normal points up, and -1 if it points down\n vec2 normal = mod(a_pos, 2.0);\n normal.y = sign(normal.y - 0.5);\n v_normal = normal;\n\n // Scale the extrusion vector down to a normal and then up by the line width\n // of this vertex.\n vec4 dist = vec4(u_linewidth.s * a_extrude * scale, 0.0, 0.0);\n\n // Calculate the offset when drawing a line that is to the side of the actual line.\n // We do this by creating a vector that points towards the extrude, but rotate\n // it when we're drawing round end points (a_direction = -1 or 1) since their\n // extrude vector points in another direction.\n float u = 0.5 * a_direction;\n float t = 1.0 - abs(u);\n vec2 offset = u_offset * a_extrude * scale * normal.y * mat2(t, -u, u, t);\n\n // Remove the texture normal bit of the position before scaling it with the\n // model/view matrix.\n gl_Position = u_matrix * vec4(floor(a_pos * 0.5) + (offset + dist.xy) / u_ratio, 0.0, 1.0);\n\n v_tex_a = vec2(a_linesofar * u_patternscale_a.x, normal.y * u_patternscale_a.y + u_tex_y_a);\n v_tex_b = vec2(a_linesofar * u_patternscale_b.x, normal.y * u_patternscale_b.y + u_tex_y_b);\n\n // position of y on the screen\n float y = gl_Position.y / gl_Position.w;\n\n // how much features are squished in the y direction by the tilt\n float squish_scale = length(a_extrude) / length(u_antialiasingmatrix * a_extrude);\n\n // how much features are squished in all directions by the perspectiveness\n float perspective_scale = 1.0 / (1.0 - min(y * u_extra, 0.9));\n\n v_gamma_scale = perspective_scale * squish_scale;\n}\n" - }, - outline: { - fragment: "precision mediump float;\n\nuniform vec4 u_color;\n\nvarying vec2 v_pos;\n\nvoid main() {\n float dist = length(v_pos - gl_FragCoord.xy);\n float alpha = smoothstep(1.0, 0.0, dist);\n gl_FragColor = u_color * alpha;\n}\n", - vertex: "precision mediump float;\n\nattribute vec2 a_pos;\n\nuniform highp mat4 u_matrix;\nuniform vec2 u_world;\n\nvarying vec2 v_pos;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n v_pos = (gl_Position.xy/gl_Position.w + 1.0) / 2.0 * u_world;\n}\n" - }, - pattern: { - fragment: "precision mediump float;\n\nuniform float u_opacity;\nuniform vec2 u_pattern_tl_a;\nuniform vec2 u_pattern_br_a;\nuniform vec2 u_pattern_tl_b;\nuniform vec2 u_pattern_br_b;\nuniform float u_mix;\n\nuniform sampler2D u_image;\n\nvarying vec2 v_pos_a;\nvarying vec2 v_pos_b;\n\nvoid main() {\n\n vec2 imagecoord = mod(v_pos_a, 1.0);\n vec2 pos = mix(u_pattern_tl_a, u_pattern_br_a, imagecoord);\n vec4 color1 = texture2D(u_image, pos);\n\n vec2 imagecoord_b = mod(v_pos_b, 1.0);\n vec2 pos2 = mix(u_pattern_tl_b, u_pattern_br_b, imagecoord_b);\n vec4 color2 = texture2D(u_image, pos2);\n\n gl_FragColor = mix(color1, color2, u_mix) * u_opacity;\n}\n", - vertex: "precision mediump float;\n\nuniform highp mat4 u_matrix;\nuniform vec2 u_patternscale_a;\nuniform vec2 u_patternscale_b;\nuniform vec2 u_offset_a;\nuniform vec2 u_offset_b;\n\nattribute vec2 a_pos;\n\nvarying vec2 v_pos_a;\nvarying vec2 v_pos_b;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n v_pos_a = u_patternscale_a * a_pos + u_offset_a;\n v_pos_b = u_patternscale_b * a_pos + u_offset_b;\n}\n" - }, - raster: { - fragment: "precision mediump float;\n\nuniform float u_opacity0;\nuniform float u_opacity1;\nuniform sampler2D u_image0;\nuniform sampler2D u_image1;\nvarying vec2 v_pos0;\nvarying vec2 v_pos1;\n\nuniform float u_brightness_low;\nuniform float u_brightness_high;\n\nuniform float u_saturation_factor;\nuniform float u_contrast_factor;\nuniform vec3 u_spin_weights;\n\nvoid main() {\n\n // read and cross-fade colors from the main and parent tiles\n vec4 color0 = texture2D(u_image0, v_pos0);\n vec4 color1 = texture2D(u_image1, v_pos1);\n vec4 color = color0 * u_opacity0 + color1 * u_opacity1;\n vec3 rgb = color.rgb;\n\n // spin\n rgb = vec3(\n dot(rgb, u_spin_weights.xyz),\n dot(rgb, u_spin_weights.zxy),\n dot(rgb, u_spin_weights.yzx));\n\n // saturation\n float average = (color.r + color.g + color.b) / 3.0;\n rgb += (average - rgb) * u_saturation_factor;\n\n // contrast\n rgb = (rgb - 0.5) * u_contrast_factor + 0.5;\n\n // brightness\n vec3 u_high_vec = vec3(u_brightness_low, u_brightness_low, u_brightness_low);\n vec3 u_low_vec = vec3(u_brightness_high, u_brightness_high, u_brightness_high);\n\n gl_FragColor = vec4(mix(u_high_vec, u_low_vec, rgb), color.a);\n}\n", - vertex: "precision mediump float;\n\nuniform highp mat4 u_matrix;\nuniform vec2 u_tl_parent;\nuniform float u_scale_parent;\nuniform float u_buffer_scale;\n\nattribute vec2 a_pos;\nattribute vec2 a_texture_pos;\n\nvarying vec2 v_pos0;\nvarying vec2 v_pos1;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n v_pos0 = (((a_texture_pos / 32767.0) - 0.5) / u_buffer_scale ) + 0.5;\n v_pos1 = (v_pos0 * u_scale_parent) + u_tl_parent;\n}\n" - }, - icon: { - fragment: "precision mediump float;\n\nuniform sampler2D u_texture;\n\nvarying vec2 v_tex;\nvarying float v_alpha;\n\nvoid main() {\n gl_FragColor = texture2D(u_texture, v_tex) * v_alpha;\n}\n", - vertex: "precision mediump float;\n\nattribute vec2 a_pos;\nattribute vec2 a_offset;\nattribute vec4 a_data1;\nattribute vec4 a_data2;\n\n\n// matrix is for the vertex position, exmatrix is for rotating and projecting\n// the extrusion vector.\nuniform highp mat4 u_matrix;\nuniform mat4 u_exmatrix;\nuniform float u_zoom;\nuniform float u_fadedist;\nuniform float u_minfadezoom;\nuniform float u_maxfadezoom;\nuniform float u_fadezoom;\nuniform float u_opacity;\nuniform bool u_skewed;\nuniform float u_extra;\n\nuniform vec2 u_texsize;\n\nvarying vec2 v_tex;\nvarying float v_alpha;\n\nvoid main() {\n vec2 a_tex = a_data1.xy;\n float a_labelminzoom = a_data1[2];\n vec2 a_zoom = a_data2.st;\n float a_minzoom = a_zoom[0];\n float a_maxzoom = a_zoom[1];\n\n float a_fadedist = 10.0;\n\n // u_zoom is the current zoom level adjusted for the change in font size\n float z = 2.0 - step(a_minzoom, u_zoom) - (1.0 - step(a_maxzoom, u_zoom));\n\n // fade out labels\n float alpha = clamp((u_fadezoom - a_labelminzoom) / u_fadedist, 0.0, 1.0);\n\n if (u_fadedist >= 0.0) {\n v_alpha = alpha;\n } else {\n v_alpha = 1.0 - alpha;\n }\n if (u_maxfadezoom < a_labelminzoom) {\n v_alpha = 0.0;\n }\n if (u_minfadezoom >= a_labelminzoom) {\n v_alpha = 1.0;\n }\n\n // if label has been faded out, clip it\n z += step(v_alpha, 0.0);\n\n if (u_skewed) {\n vec4 extrude = u_exmatrix * vec4(a_offset / 64.0, 0, 0);\n gl_Position = u_matrix * vec4(a_pos + extrude.xy, 0, 1);\n gl_Position.z += z * gl_Position.w;\n } else {\n vec4 extrude = u_exmatrix * vec4(a_offset / 64.0, z, 0);\n gl_Position = u_matrix * vec4(a_pos, 0, 1) + extrude;\n }\n\n v_tex = a_tex / u_texsize;\n\n v_alpha *= u_opacity;\n}\n" - }, - sdf: { - fragment: "precision mediump float;\n\nuniform sampler2D u_texture;\nuniform vec4 u_color;\nuniform float u_buffer;\nuniform float u_gamma;\n\nvarying vec2 v_tex;\nvarying float v_alpha;\nvarying float v_gamma_scale;\n\nvoid main() {\n float gamma = u_gamma * v_gamma_scale;\n float dist = texture2D(u_texture, v_tex).a;\n float alpha = smoothstep(u_buffer - gamma, u_buffer + gamma, dist) * v_alpha;\n gl_FragColor = u_color * alpha;\n}\n", - vertex: "precision mediump float;\n\nattribute vec2 a_pos;\nattribute vec2 a_offset;\nattribute vec4 a_data1;\nattribute vec4 a_data2;\n\n\n// matrix is for the vertex position, exmatrix is for rotating and projecting\n// the extrusion vector.\nuniform highp mat4 u_matrix;\nuniform mat4 u_exmatrix;\n\nuniform float u_zoom;\nuniform float u_fadedist;\nuniform float u_minfadezoom;\nuniform float u_maxfadezoom;\nuniform float u_fadezoom;\nuniform bool u_skewed;\nuniform float u_extra;\n\nuniform vec2 u_texsize;\n\nvarying vec2 v_tex;\nvarying float v_alpha;\nvarying float v_gamma_scale;\n\nvoid main() {\n vec2 a_tex = a_data1.xy;\n float a_labelminzoom = a_data1[2];\n vec2 a_zoom = a_data2.st;\n float a_minzoom = a_zoom[0];\n float a_maxzoom = a_zoom[1];\n\n // u_zoom is the current zoom level adjusted for the change in font size\n float z = 2.0 - step(a_minzoom, u_zoom) - (1.0 - step(a_maxzoom, u_zoom));\n\n // fade out labels\n float alpha = clamp((u_fadezoom - a_labelminzoom) / u_fadedist, 0.0, 1.0);\n\n if (u_fadedist >= 0.0) {\n v_alpha = alpha;\n } else {\n v_alpha = 1.0 - alpha;\n }\n if (u_maxfadezoom < a_labelminzoom) {\n v_alpha = 0.0;\n }\n if (u_minfadezoom >= a_labelminzoom) {\n v_alpha = 1.0;\n }\n\n // if label has been faded out, clip it\n z += step(v_alpha, 0.0);\n\n if (u_skewed) {\n vec4 extrude = u_exmatrix * vec4(a_offset / 64.0, 0, 0);\n gl_Position = u_matrix * vec4(a_pos + extrude.xy, 0, 1);\n gl_Position.z += z * gl_Position.w;\n } else {\n vec4 extrude = u_exmatrix * vec4(a_offset / 64.0, z, 0);\n gl_Position = u_matrix * vec4(a_pos, 0, 1) + extrude;\n }\n\n // position of y on the screen\n float y = gl_Position.y / gl_Position.w;\n // how much features are squished in all directions by the perspectiveness\n float perspective_scale = 1.0 / (1.0 - y * u_extra);\n v_gamma_scale = perspective_scale;\n\n v_tex = a_tex / u_texsize;\n}\n" - }, - collisionbox: { - fragment: "precision mediump float;\n\nuniform float u_zoom;\nuniform float u_maxzoom;\n\nvarying float v_max_zoom;\nvarying float v_placement_zoom;\n\nvoid main() {\n\n float alpha = 0.5;\n\n gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0) * alpha;\n\n if (v_placement_zoom > u_zoom) {\n gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * alpha;\n }\n\n if (u_zoom >= v_max_zoom) {\n gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0) * alpha * 0.25;\n }\n\n if (v_placement_zoom >= u_maxzoom) {\n gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0) * alpha * 0.2;\n }\n}\n", - vertex: "precision mediump float;\n\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nattribute vec2 a_data;\n\nuniform highp mat4 u_matrix;\nuniform float u_scale;\n\nvarying float v_max_zoom;\nvarying float v_placement_zoom;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos + a_extrude / u_scale, 0.0, 1.0);\n\n v_max_zoom = a_data.x;\n v_placement_zoom = a_data.y;\n}\n" - } +/** + * Performs a linear interpolation between two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec2} out + */ +vec2.lerp = function (out, a, b, t) { + var ax = a[0], + ay = a[1]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + return out; }; -},{"path":8}],44:[function(require,module,exports){ -'use strict'; - -var util = require('../util/util'); -var Evented = require('../util/evented'); -var TilePyramid = require('./tile_pyramid'); -var Source = require('./source'); -var urlResolve = require('resolve-url'); -var EXTENT = require('../data/buffer').EXTENT; - -module.exports = GeoJSONSource; - /** - * Create a GeoJSON data source instance given an options object - * @class GeoJSONSource - * @param {Object} [options] - * @param {Object|string} options.data A GeoJSON data object or URL to it. The latter is preferable in case of large GeoJSON files. - * @param {number} [options.maxzoom=14] Maximum zoom to preserve detail at. - * @param {number} [options.buffer] Tile buffer on each side in pixels. - * @param {number} [options.tolerance] Simplification tolerance (higher means simpler) in pixels. - * @param {number} [options.cluster] If the data is a collection of point features, setting this to true clusters the points by radius into groups. - * @param {number} [options.clusterRadius=50] Radius of each cluster when clustering points, in pixels. - * @param {number} [options.clusterMaxZoom] Max zoom to cluster points on. Defaults to one zoom less than `maxzoom` (so that last zoom features are not clustered). - - * @example - * var sourceObj = new mapboxgl.GeoJSONSource({ - * data: { - * "type": "FeatureCollection", - * "features": [{ - * "type": "Feature", - * "geometry": { - * "type": "Point", - * "coordinates": [ - * -76.53063297271729, - * 39.18174077994108 - * ] - * } - * }] - * } - * }); - * map.addSource('some id', sourceObj); // add - * map.removeSource('some id'); // remove + * Generates a random vector with the given scale + * + * @param {vec2} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec2} out */ -function GeoJSONSource(options) { - options = options || {}; - - this._data = options.data; - - if (options.maxzoom !== undefined) this.maxzoom = options.maxzoom; - - var scale = EXTENT / this.tileSize; - - this.geojsonVtOptions = { - buffer: (options.buffer !== undefined ? options.buffer : 128) * scale, - tolerance: (options.tolerance !== undefined ? options.tolerance : 0.375) * scale, - extent: EXTENT, - maxZoom: this.maxzoom - }; - - this.cluster = options.cluster || false; - this.superclusterOptions = { - maxZoom: Math.max(options.clusterMaxZoom, this.maxzoom - 1) || (this.maxzoom - 1), - extent: EXTENT, - radius: (options.clusterRadius || 50) * scale, - log: false - }; - - this._pyramid = new TilePyramid({ - tileSize: this.tileSize, - minzoom: this.minzoom, - maxzoom: this.maxzoom, - reparseOverscaled: true, - cacheSize: 20, - load: this._loadTile.bind(this), - abort: this._abortTile.bind(this), - unload: this._unloadTile.bind(this), - add: this._addTile.bind(this), - remove: this._removeTile.bind(this), - redoPlacement: this._redoTilePlacement.bind(this) - }); -} - -GeoJSONSource.prototype = util.inherit(Evented, /** @lends GeoJSONSource.prototype */{ - minzoom: 0, - maxzoom: 14, - tileSize: 512, - _dirty: true, - isTileClipped: true, - - /** - * Update source geojson data and rerender map - * - * @param {Object|string} data A GeoJSON data object or URL to it. The latter is preferable in case of large GeoJSON files. - * @returns {GeoJSONSource} this - */ - setData: function(data) { - this._data = data; - this._dirty = true; +vec2.random = function (out, scale) { + scale = scale || 1.0; + var r = glMatrix.RANDOM() * 2.0 * Math.PI; + out[0] = Math.cos(r) * scale; + out[1] = Math.sin(r) * scale; + return out; +}; - this.fire('change'); +/** + * Transforms the vec2 with a mat2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat2} m matrix to transform with + * @returns {vec2} out + */ +vec2.transformMat2 = function(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[2] * y; + out[1] = m[1] * x + m[3] * y; + return out; +}; - if (this.map) - this.update(this.map.transform); +/** + * Transforms the vec2 with a mat2d + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat2d} m matrix to transform with + * @returns {vec2} out + */ +vec2.transformMat2d = function(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[2] * y + m[4]; + out[1] = m[1] * x + m[3] * y + m[5]; + return out; +}; - return this; - }, +/** + * Transforms the vec2 with a mat3 + * 3rd vector component is implicitly '1' + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat3} m matrix to transform with + * @returns {vec2} out + */ +vec2.transformMat3 = function(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[3] * y + m[6]; + out[1] = m[1] * x + m[4] * y + m[7]; + return out; +}; - onAdd: function(map) { - this.map = map; - }, +/** + * Transforms the vec2 with a mat4 + * 3rd vector component is implicitly '0' + * 4th vector component is implicitly '1' + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat4} m matrix to transform with + * @returns {vec2} out + */ +vec2.transformMat4 = function(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[4] * y + m[12]; + out[1] = m[1] * x + m[5] * y + m[13]; + return out; +}; - loaded: function() { - return this._loaded && this._pyramid.loaded(); - }, +/** + * Perform some operation over an array of vec2s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ +vec2.forEach = (function() { + var vec = vec2.create(); - update: function(transform) { - if (this._dirty) { - this._updateData(); + return function(a, stride, offset, count, fn, arg) { + var i, l; + if(!stride) { + stride = 2; } - if (this._loaded) { - this._pyramid.update(this.used, transform); + if(!offset) { + offset = 0; } - }, - - reload: function() { - if (this._loaded) { - this._pyramid.reload(); + + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; } - }, - - serialize: function() { - return { - type: 'geojson', - data: this._data - }; - }, - getVisibleCoordinates: Source._getVisibleCoordinates, - getTile: Source._getTile, - - featuresAt: Source._vectorFeaturesAt, - featuresIn: Source._vectorFeaturesIn, - - _updateData: function() { - this._dirty = false; - var data = this._data; - if (typeof data === 'string' && typeof window != 'undefined') { - data = urlResolve(window.location.href, data); + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; } - this.workerID = this.dispatcher.send('parse geojson', { - data: data, - tileSize: this.tileSize, - source: this.id, - geojsonVtOptions: this.geojsonVtOptions, - cluster: this.cluster, - superclusterOptions: this.superclusterOptions - }, function(err) { - this._loaded = true; - if (err) { - this.fire('error', {error: err}); - } else { - this._pyramid.reload(); - this.fire('change'); - } + + return a; + }; +})(); - }.bind(this)); - }, +/** + * Returns a string representation of a vector + * + * @param {vec2} vec vector to represent as a string + * @returns {String} string representation of the vector + */ +vec2.str = function (a) { + return 'vec2(' + a[0] + ', ' + a[1] + ')'; +}; - _loadTile: function(tile) { - var overscaling = tile.coord.z > this.maxzoom ? Math.pow(2, tile.coord.z - this.maxzoom) : 1; - var params = { - uid: tile.uid, - coord: tile.coord, - zoom: tile.coord.z, - maxZoom: this.maxzoom, - tileSize: this.tileSize, - source: this.id, - overscaling: overscaling, - angle: this.map.transform.angle, - pitch: this.map.transform.pitch, - collisionDebug: this.map.collisionDebug - }; +/** + * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===) + * + * @param {vec2} a The first vector. + * @param {vec2} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ +vec2.exactEquals = function (a, b) { + return a[0] === b[0] && a[1] === b[1]; +}; - tile.workerID = this.dispatcher.send('load geojson tile', params, function(err, data) { +/** + * Returns whether or not the vectors have approximately the same elements in the same position. + * + * @param {vec2} a The first vector. + * @param {vec2} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ +vec2.equals = function (a, b) { + var a0 = a[0], a1 = a[1]; + var b0 = b[0], b1 = b[1]; + return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && + Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1))); +}; - tile.unloadVectorData(this.map.painter); +module.exports = vec2; - if (tile.aborted) - return; +},{"./common.js":30}],37:[function(require,module,exports){ +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - if (err) { - this.fire('tile.error', {tile: tile}); - return; - } +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: - tile.loadVectorData(data); +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - if (tile.redoWhenDone) { - tile.redoWhenDone = false; - tile.redoPlacement(this); - } +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. */ - this.fire('tile.load', {tile: tile}); +var glMatrix = require("./common.js"); - }.bind(this), this.workerID); - }, - - _abortTile: function(tile) { - tile.aborted = true; - }, - - _addTile: function(tile) { - this.fire('tile.add', {tile: tile}); - }, - - _removeTile: function(tile) { - this.fire('tile.remove', {tile: tile}); - }, - - _unloadTile: function(tile) { - tile.unloadVectorData(this.map.painter); - this.dispatcher.send('remove tile', { uid: tile.uid, source: this.id }, null, tile.workerID); - }, - - redoPlacement: Source.redoPlacement, - - _redoTilePlacement: function(tile) { - tile.redoPlacement(this); - } -}); - -},{"../data/buffer":17,"../util/evented":107,"../util/util":113,"./source":48,"./tile_pyramid":51,"resolve-url":164}],45:[function(require,module,exports){ -'use strict'; - -var Point = require('point-geometry'); -var VectorTileFeature = require('vector-tile').VectorTileFeature; -var EXTENT = require('../data/buffer').EXTENT; - -module.exports = GeoJSONWrapper; - -// conform to vectortile api -function GeoJSONWrapper(features) { - this.features = features; - this.length = features.length; -} +/** + * @class 3 Dimensional Vector + * @name vec3 + */ +var vec3 = {}; -GeoJSONWrapper.prototype.feature = function(i) { - return new FeatureWrapper(this.features[i]); +/** + * Creates a new, empty vec3 + * + * @returns {vec3} a new 3D vector + */ +vec3.create = function() { + var out = new glMatrix.ARRAY_TYPE(3); + out[0] = 0; + out[1] = 0; + out[2] = 0; + return out; }; -function FeatureWrapper(feature) { - this.type = feature.type; - this.rawGeometry = feature.type === 1 ? [feature.geometry] : feature.geometry; - this.properties = feature.tags; - this.extent = EXTENT; -} - -FeatureWrapper.prototype.loadGeometry = function() { - var rings = this.rawGeometry; - this.geometry = []; +/** + * Creates a new vec3 initialized with values from an existing vector + * + * @param {vec3} a vector to clone + * @returns {vec3} a new 3D vector + */ +vec3.clone = function(a) { + var out = new glMatrix.ARRAY_TYPE(3); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + return out; +}; - for (var i = 0; i < rings.length; i++) { - var ring = rings[i], - newRing = []; - for (var j = 0; j < ring.length; j++) { - newRing.push(new Point(ring[j][0], ring[j][1])); - } - this.geometry.push(newRing); - } - return this.geometry; +/** + * Creates a new vec3 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @returns {vec3} a new 3D vector + */ +vec3.fromValues = function(x, y, z) { + var out = new glMatrix.ARRAY_TYPE(3); + out[0] = x; + out[1] = y; + out[2] = z; + return out; }; -FeatureWrapper.prototype.bbox = function() { - if (!this.geometry) this.loadGeometry(); +/** + * Copy the values from one vec3 to another + * + * @param {vec3} out the receiving vector + * @param {vec3} a the source vector + * @returns {vec3} out + */ +vec3.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + return out; +}; - var rings = this.geometry, - x1 = Infinity, - x2 = -Infinity, - y1 = Infinity, - y2 = -Infinity; +/** + * Set the components of a vec3 to the given values + * + * @param {vec3} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @returns {vec3} out + */ +vec3.set = function(out, x, y, z) { + out[0] = x; + out[1] = y; + out[2] = z; + return out; +}; - for (var i = 0; i < rings.length; i++) { - var ring = rings[i]; +/** + * Adds two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.add = function(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + return out; +}; - for (var j = 0; j < ring.length; j++) { - var coord = ring[j]; +/** + * Subtracts vector b from vector a + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.subtract = function(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + return out; +}; - x1 = Math.min(x1, coord.x); - x2 = Math.max(x2, coord.x); - y1 = Math.min(y1, coord.y); - y2 = Math.max(y2, coord.y); - } - } +/** + * Alias for {@link vec3.subtract} + * @function + */ +vec3.sub = vec3.subtract; - return [x1, y1, x2, y2]; +/** + * Multiplies two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.multiply = function(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; + return out; }; -FeatureWrapper.prototype.toGeoJSON = VectorTileFeature.prototype.toGeoJSON; +/** + * Alias for {@link vec3.multiply} + * @function + */ +vec3.mul = vec3.multiply; -},{"../data/buffer":17,"point-geometry":162,"vector-tile":168}],46:[function(require,module,exports){ -'use strict'; +/** + * Divides two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.divide = function(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + out[2] = a[2] / b[2]; + return out; +}; -var util = require('../util/util'); -var Tile = require('./tile'); -var LngLat = require('../geo/lng_lat'); -var Point = require('point-geometry'); -var Evented = require('../util/evented'); -var ajax = require('../util/ajax'); -var EXTENT = require('../data/buffer').EXTENT; +/** + * Alias for {@link vec3.divide} + * @function + */ +vec3.div = vec3.divide; -module.exports = ImageSource; +/** + * Math.ceil the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to ceil + * @returns {vec3} out + */ +vec3.ceil = function (out, a) { + out[0] = Math.ceil(a[0]); + out[1] = Math.ceil(a[1]); + out[2] = Math.ceil(a[2]); + return out; +}; /** - * Create an Image source instance given an options object - * @class ImageSource - * @param {Object} [options] - * @param {string} options.url A string URL of an image file - * @param {Array} options.coordinates lng, lat coordinates in order clockwise - * starting at the top left: tl, tr, br, bl - * @example - * var sourceObj = new mapboxgl.ImageSource({ - * url: 'https://www.mapbox.com/images/foo.png', - * coordinates: [ - * [-76.54335737228394, 39.18579907229748], - * [-76.52803659439087, 39.1838364847587], - * [-76.5295386314392, 39.17683392507606], - * [-76.54520273208618, 39.17876344106642] - * ] - * }); - * map.addSource('some id', sourceObj); // add - * map.removeSource('some id'); // remove + * Math.floor the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to floor + * @returns {vec3} out */ -function ImageSource(options) { - this.urls = options.urls; - this.coordinates = options.coordinates; +vec3.floor = function (out, a) { + out[0] = Math.floor(a[0]); + out[1] = Math.floor(a[1]); + out[2] = Math.floor(a[2]); + return out; +}; - ajax.getImage(options.url, function(err, image) { - // @TODO handle errors via event. - if (err) return; +/** + * Returns the minimum of two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.min = function(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + out[2] = Math.min(a[2], b[2]); + return out; +}; - this.image = image; +/** + * Returns the maximum of two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.max = function(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + out[2] = Math.max(a[2], b[2]); + return out; +}; - this.image.addEventListener('load', function() { - this.map._rerender(); - }.bind(this)); - - this._loaded = true; - - if (this.map) { - this.createTile(options.coordinates); - this.fire('change'); - } - }.bind(this)); -} - -ImageSource.prototype = util.inherit(Evented, { - onAdd: function(map) { - this.map = map; - if (this.image) { - this.createTile(); - } - }, - - /** - * Calculate which mercator tile is suitable for rendering the image in - * and create a buffer with the corner coordinates. These coordinates - * may be outside the tile, because raster tiles aren't clipped when rendering. - * @private - */ - createTile: function(cornerGeoCoords) { - var map = this.map; - var cornerZ0Coords = cornerGeoCoords.map(function(coord) { - return map.transform.locationCoordinate(LngLat.convert(coord)).zoomTo(0); - }); - - var centerCoord = this.centerCoord = util.getCoordinatesCenter(cornerZ0Coords); - - var tileCoords = cornerZ0Coords.map(function(coord) { - var zoomedCoord = coord.zoomTo(centerCoord.zoom); - return new Point( - Math.round((zoomedCoord.column - centerCoord.column) * EXTENT), - Math.round((zoomedCoord.row - centerCoord.row) * EXTENT)); - }); - - var gl = map.painter.gl; - var maxInt16 = 32767; - var array = new Int16Array([ - tileCoords[0].x, tileCoords[0].y, 0, 0, - tileCoords[1].x, tileCoords[1].y, maxInt16, 0, - tileCoords[3].x, tileCoords[3].y, 0, maxInt16, - tileCoords[2].x, tileCoords[2].y, maxInt16, maxInt16 - ]); +/** + * Math.round the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to round + * @returns {vec3} out + */ +vec3.round = function (out, a) { + out[0] = Math.round(a[0]); + out[1] = Math.round(a[1]); + out[2] = Math.round(a[2]); + return out; +}; - this.tile = new Tile(); - this.tile.buckets = {}; +/** + * Scales a vec3 by a scalar number + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec3} out + */ +vec3.scale = function(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + return out; +}; - this.tile.boundsBuffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, this.tile.boundsBuffer); - gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW); - }, +/** + * Adds two vec3's after scaling the second operand by a scalar value + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec3} out + */ +vec3.scaleAndAdd = function(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + out[2] = a[2] + (b[2] * scale); + return out; +}; - loaded: function() { - return this.image && this.image.complete; - }, +/** + * Calculates the euclidian distance between two vec3's + * + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {Number} distance between a and b + */ +vec3.distance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1], + z = b[2] - a[2]; + return Math.sqrt(x*x + y*y + z*z); +}; - update: function() { - // noop - }, +/** + * Alias for {@link vec3.distance} + * @function + */ +vec3.dist = vec3.distance; - reload: function() { - // noop - }, +/** + * Calculates the squared euclidian distance between two vec3's + * + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {Number} squared distance between a and b + */ +vec3.squaredDistance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1], + z = b[2] - a[2]; + return x*x + y*y + z*z; +}; - prepare: function() { - if (!this._loaded || !this.loaded()) return; +/** + * Alias for {@link vec3.squaredDistance} + * @function + */ +vec3.sqrDist = vec3.squaredDistance; - var painter = this.map.painter; - var gl = painter.gl; +/** + * Calculates the length of a vec3 + * + * @param {vec3} a vector to calculate length of + * @returns {Number} length of a + */ +vec3.length = function (a) { + var x = a[0], + y = a[1], + z = a[2]; + return Math.sqrt(x*x + y*y + z*z); +}; - if (!this.tile.texture) { - this.tile.texture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, this.tile.texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.image); - } else { - gl.bindTexture(gl.TEXTURE_2D, this.tile.texture); - gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.image); - } - }, +/** + * Alias for {@link vec3.length} + * @function + */ +vec3.len = vec3.length; - getVisibleCoordinates: function() { - if (this.centerCoord) return [this.centerCoord]; - else return []; - }, +/** + * Calculates the squared length of a vec3 + * + * @param {vec3} a vector to calculate squared length of + * @returns {Number} squared length of a + */ +vec3.squaredLength = function (a) { + var x = a[0], + y = a[1], + z = a[2]; + return x*x + y*y + z*z; +}; - getTile: function() { - return this.tile; - }, +/** + * Alias for {@link vec3.squaredLength} + * @function + */ +vec3.sqrLen = vec3.squaredLength; - /** - * An ImageSource doesn't have any vector features that could - * be selectable, so always return an empty array. - * @private - */ - featuresAt: function(point, params, callback) { - return callback(null, []); - }, +/** + * Negates the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to negate + * @returns {vec3} out + */ +vec3.negate = function(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + return out; +}; - featuresIn: function(bbox, params, callback) { - return callback(null, []); - }, +/** + * Returns the inverse of the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to invert + * @returns {vec3} out + */ +vec3.inverse = function(out, a) { + out[0] = 1.0 / a[0]; + out[1] = 1.0 / a[1]; + out[2] = 1.0 / a[2]; + return out; +}; - serialize: function() { - return { - type: 'image', - urls: this.urls, - coordinates: this.coordinates - }; +/** + * Normalize a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to normalize + * @returns {vec3} out + */ +vec3.normalize = function(out, a) { + var x = a[0], + y = a[1], + z = a[2]; + var len = x*x + y*y + z*z; + if (len > 0) { + //TODO: evaluate use of glm_invsqrt here? + len = 1 / Math.sqrt(len); + out[0] = a[0] * len; + out[1] = a[1] * len; + out[2] = a[2] * len; } -}); - -},{"../data/buffer":17,"../geo/lng_lat":26,"../util/ajax":101,"../util/evented":107,"../util/util":113,"./tile":49,"point-geometry":162}],47:[function(require,module,exports){ -'use strict'; - -var util = require('../util/util'); -var ajax = require('../util/ajax'); -var Evented = require('../util/evented'); -var Source = require('./source'); -var normalizeURL = require('../util/mapbox').normalizeTileURL; - -module.exports = RasterTileSource; - -function RasterTileSource(options) { - util.extend(this, util.pick(options, ['url', 'tileSize'])); + return out; +}; - Source._loadTileJSON.call(this, options); -} +/** + * Calculates the dot product of two vec3's + * + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {Number} dot product of a and b + */ +vec3.dot = function (a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +}; -RasterTileSource.prototype = util.inherit(Evented, { - minzoom: 0, - maxzoom: 22, - roundZoom: true, - tileSize: 512, - _loaded: false, +/** + * Computes the cross product of two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.cross = function(out, a, b) { + var ax = a[0], ay = a[1], az = a[2], + bx = b[0], by = b[1], bz = b[2]; - onAdd: function(map) { - this.map = map; - }, + out[0] = ay * bz - az * by; + out[1] = az * bx - ax * bz; + out[2] = ax * by - ay * bx; + return out; +}; - loaded: function() { - return this._pyramid && this._pyramid.loaded(); - }, - - update: function(transform) { - if (this._pyramid) { - this._pyramid.update(this.used, transform, this.map.style.rasterFadeDuration); - } - }, - - reload: function() { - // noop - }, - - serialize: function() { - return { - type: 'raster', - url: this.url, - tileSize: this.tileSize - }; - }, - - getVisibleCoordinates: Source._getVisibleCoordinates, - getTile: Source._getTile, - - _loadTile: function(tile) { - var url = normalizeURL(tile.coord.url(this.tiles), this.url); - - tile.request = ajax.getImage(url, done.bind(this)); - - function done(err, img) { - delete tile.request; - - if (tile.aborted) - return; - - if (err) { - tile.errored = true; - this.fire('tile.error', {tile: tile, error: err}); - return; - } - - var gl = this.map.painter.gl; - tile.texture = this.map.painter.getTexture(img.width); - if (tile.texture) { - gl.bindTexture(gl.TEXTURE_2D, tile.texture); - gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, img); - } else { - tile.texture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, tile.texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img); - tile.texture.size = img.width; - } - gl.generateMipmap(gl.TEXTURE_2D); - - tile.timeAdded = new Date().getTime(); - this.map.animationLoop.set(this.style.rasterFadeDuration); - - tile.source = this; - tile.loaded = true; - - this.fire('tile.load', {tile: tile}); - } - }, - - _abortTile: function(tile) { - tile.aborted = true; - - if (tile.request) { - tile.request.abort(); - delete tile.request; - } - }, - - _addTile: function(tile) { - this.fire('tile.add', {tile: tile}); - }, - - _removeTile: function(tile) { - this.fire('tile.remove', {tile: tile}); - }, - - _unloadTile: function(tile) { - if (tile.texture) this.map.painter.saveTexture(tile.texture); - }, - - featuresAt: function(point, params, callback) { - callback(null, []); - }, - - featuresIn: function(bbox, params, callback) { - callback(null, []); - } -}); - -},{"../util/ajax":101,"../util/evented":107,"../util/mapbox":110,"../util/util":113,"./source":48}],48:[function(require,module,exports){ -'use strict'; - -var util = require('../util/util'); -var ajax = require('../util/ajax'); -var browser = require('../util/browser'); -var TilePyramid = require('./tile_pyramid'); -var normalizeURL = require('../util/mapbox').normalizeSourceURL; -var TileCoord = require('./tile_coord'); - -exports._loadTileJSON = function(options) { - var loaded = function(err, tileJSON) { - if (err) { - this.fire('error', {error: err}); - return; - } - - util.extend(this, util.pick(tileJSON, - ['tiles', 'minzoom', 'maxzoom', 'attribution'])); - - if (tileJSON.vector_layers) { - this.vectorLayers = tileJSON.vector_layers; - this.vectorLayerIds = this.vectorLayers.map(function(layer) { return layer.id; }); - } - - this._pyramid = new TilePyramid({ - tileSize: this.tileSize, - cacheSize: 20, - minzoom: this.minzoom, - maxzoom: this.maxzoom, - roundZoom: this.roundZoom, - reparseOverscaled: this.reparseOverscaled, - load: this._loadTile.bind(this), - abort: this._abortTile.bind(this), - unload: this._unloadTile.bind(this), - add: this._addTile.bind(this), - remove: this._removeTile.bind(this), - redoPlacement: this._redoTilePlacement ? this._redoTilePlacement.bind(this) : undefined - }); - - this.fire('load'); - }.bind(this); - - if (options.url) { - ajax.getJSON(normalizeURL(options.url), loaded); - } else { - browser.frame(loaded.bind(this, null, options)); - } -}; - -exports.redoPlacement = function() { - if (!this._pyramid) { - return; - } - - var ids = this._pyramid.orderedIDs(); - for (var i = 0; i < ids.length; i++) { - var tile = this._pyramid.getTile(ids[i]); - this._redoTilePlacement(tile); - } +/** + * Performs a linear interpolation between two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec3} out + */ +vec3.lerp = function (out, a, b, t) { + var ax = a[0], + ay = a[1], + az = a[2]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + out[2] = az + t * (b[2] - az); + return out; }; -exports._getTile = function(coord) { - return this._pyramid.getTile(coord.id); +/** + * Performs a hermite interpolation with two control points + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @param {vec3} c the third operand + * @param {vec3} d the fourth operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec3} out + */ +vec3.hermite = function (out, a, b, c, d, t) { + var factorTimes2 = t * t, + factor1 = factorTimes2 * (2 * t - 3) + 1, + factor2 = factorTimes2 * (t - 2) + t, + factor3 = factorTimes2 * (t - 1), + factor4 = factorTimes2 * (3 - 2 * t); + + out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4; + out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4; + out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4; + + return out; }; -exports._getVisibleCoordinates = function() { - if (!this._pyramid) return []; - else return this._pyramid.renderedIDs().map(TileCoord.fromID); +/** + * Performs a bezier interpolation with two control points + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @param {vec3} c the third operand + * @param {vec3} d the fourth operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec3} out + */ +vec3.bezier = function (out, a, b, c, d, t) { + var inverseFactor = 1 - t, + inverseFactorTimesTwo = inverseFactor * inverseFactor, + factorTimes2 = t * t, + factor1 = inverseFactorTimesTwo * inverseFactor, + factor2 = 3 * t * inverseFactorTimesTwo, + factor3 = 3 * factorTimes2 * inverseFactor, + factor4 = factorTimes2 * t; + + out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4; + out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4; + out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4; + + return out; }; -exports._vectorFeaturesAt = function(coord, params, callback) { - if (!this._pyramid) - return callback(null, []); +/** + * Generates a random vector with the given scale + * + * @param {vec3} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec3} out + */ +vec3.random = function (out, scale) { + scale = scale || 1.0; - var result = this._pyramid.tileAt(coord); - if (!result) - return callback(null, []); + var r = glMatrix.RANDOM() * 2.0 * Math.PI; + var z = (glMatrix.RANDOM() * 2.0) - 1.0; + var zScale = Math.sqrt(1.0-z*z) * scale; - this.dispatcher.send('query features', { - uid: result.tile.uid, - x: result.x, - y: result.y, - scale: result.scale, - source: this.id, - params: params - }, callback, result.tile.workerID); + out[0] = Math.cos(r) * zScale; + out[1] = Math.sin(r) * zScale; + out[2] = z * scale; + return out; }; - -exports._vectorFeaturesIn = function(bounds, params, callback) { - if (!this._pyramid) - return callback(null, []); - - var results = this._pyramid.tilesIn(bounds); - if (!results) - return callback(null, []); - - util.asyncAll(results, function queryTile(result, cb) { - this.dispatcher.send('query features', { - uid: result.tile.uid, - source: this.id, - minX: result.minX, - maxX: result.maxX, - minY: result.minY, - maxY: result.maxY, - params: params - }, cb, result.tile.workerID); - }.bind(this), function done(err, features) { - callback(err, Array.prototype.concat.apply([], features)); - }); +/** + * Transforms the vec3 with a mat4. + * 4th vector component is implicitly '1' + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to transform + * @param {mat4} m matrix to transform with + * @returns {vec3} out + */ +vec3.transformMat4 = function(out, a, m) { + var x = a[0], y = a[1], z = a[2], + w = m[3] * x + m[7] * y + m[11] * z + m[15]; + w = w || 1.0; + out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w; + out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w; + out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w; + return out; }; -/* - * Create a tiled data source instance given an options object +/** + * Transforms the vec3 with a mat3. * - * @param {Object} options - * @param {string} options.type Either `raster` or `vector`. - * @param {string} options.url A tile source URL. This should either be `mapbox://{mapid}` or a full `http[s]` url that points to a TileJSON endpoint. - * @param {Array} options.tiles An array of tile sources. If `url` is not specified, `tiles` can be used instead to specify tile sources, as in the TileJSON spec. Other TileJSON keys such as `minzoom` and `maxzoom` can be specified in a source object if `tiles` is used. - * @param {string} options.id An optional `id` to assign to the source - * @param {number} [options.tileSize=512] Optional tile size (width and height in pixels, assuming tiles are square). This option is only configurable for raster sources - * @param {number} options.cacheSize Optional max number of tiles to cache at any given time - * @example - * var sourceObj = new mapboxgl.Source.create({ - * type: 'vector', - * url: 'mapbox://mapbox.mapbox-streets-v5' - * }); - * map.addSource('some id', sourceObj); // add - * map.removeSource('some id'); // remove - */ -exports.create = function(source) { - // This is not at file scope in order to avoid a circular require. - var sources = { - vector: require('./vector_tile_source'), - raster: require('./raster_tile_source'), - geojson: require('./geojson_source'), - video: require('./video_source'), - image: require('./image_source') - }; - - for (var type in sources) { - if (source instanceof sources[type]) { - return source; - } - } - - return new sources[source.type](source); + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to transform + * @param {mat4} m the 3x3 matrix to transform with + * @returns {vec3} out + */ +vec3.transformMat3 = function(out, a, m) { + var x = a[0], y = a[1], z = a[2]; + out[0] = x * m[0] + y * m[3] + z * m[6]; + out[1] = x * m[1] + y * m[4] + z * m[7]; + out[2] = x * m[2] + y * m[5] + z * m[8]; + return out; }; -},{"../util/ajax":101,"../util/browser":102,"../util/mapbox":110,"../util/util":113,"./geojson_source":44,"./image_source":46,"./raster_tile_source":47,"./tile_coord":50,"./tile_pyramid":51,"./vector_tile_source":52,"./video_source":53}],49:[function(require,module,exports){ -'use strict'; - -var util = require('../util/util'); -var Buffer = require('../data/buffer'); -var EXTENT = require('../data/buffer').EXTENT; - -module.exports = Tile; - /** - * A tile object is the combination of a Coordinate, which defines - * its place, as well as a unique ID and data tracking for its content + * Transforms the vec3 with a quat * - * @param {Coordinate} coord - * @param {number} size - * @private + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to transform + * @param {quat} q quaternion to transform with + * @returns {vec3} out */ -function Tile(coord, size, sourceMaxZoom) { - this.coord = coord; - this.uid = util.uniqueId(); - this.loaded = false; - this.uses = 0; - this.tileSize = size; - this.sourceMaxZoom = sourceMaxZoom; -} +vec3.transformQuat = function(out, a, q) { + // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations -Tile.prototype = { + var x = a[0], y = a[1], z = a[2], + qx = q[0], qy = q[1], qz = q[2], qw = q[3], - /** - * Converts a pixel value at a the given zoom level to tile units. - * - * The shaders mostly calculate everything in tile units so style - * properties need to be converted from pixels to tile units using this. - * - * For example, a translation by 30 pixels at zoom 6.5 will be a - * translation by pixelsToTileUnits(30, 6.5) tile units. - * - * @param {number} pixelValue - * @param {number} z - * @returns {number} value in tile units - * @private - */ - pixelsToTileUnits: function(pixelValue, z) { - return pixelValue * (EXTENT / (this.tileSize * Math.pow(2, z - this.coord.z))); - }, - - /** - * Given a coordinate position, zoom that coordinate to my zoom and - * scale and return a position in x, y, scale - * @param {Coordinate} coord - * @returns {Object} position - * @private - */ - positionAt: function(coord) { - var zoomedCoord = coord.zoomTo(Math.min(this.coord.z, this.sourceMaxZoom)); - return { - x: (zoomedCoord.column - this.coord.x) * EXTENT, - y: (zoomedCoord.row - this.coord.y) * EXTENT - }; - }, - - /** - * Given a data object with a 'buffers' property, load it into - * this tile's elementGroups and buffers properties and set loaded - * to true. If the data is null, like in the case of an empty - * GeoJSON tile, no-op but still set loaded to true. - * @param {Object} data - * @returns {undefined} - * @private - */ - loadVectorData: function(data) { - this.loaded = true; - - // empty GeoJSON tile - if (!data) return; - - this.buffers = unserializeBuffers(data.buffers); - this.elementGroups = data.elementGroups; - }, - - /** - * given a data object and a GL painter, destroy and re-create - * all of its buffers. - * @param {Object} data - * @param {Object} painter - * @returns {undefined} - * @private - */ - reloadSymbolData: function(data, painter) { - - if (!this.buffers) { - // the tile has been destroyed - return; - } - - if (this.buffers.glyphVertex) this.buffers.glyphVertex.destroy(painter.gl); - if (this.buffers.glyphElement) this.buffers.glyphElement.destroy(painter.gl); - if (this.buffers.iconVertex) this.buffers.iconVertex.destroy(painter.gl); - if (this.buffers.iconElement) this.buffers.iconElement.destroy(painter.gl); - if (this.buffers.collisionBoxVertex) this.buffers.collisionBoxVertex.destroy(painter.gl); - - var buffers = unserializeBuffers(data.buffers); - this.buffers.glyphVertex = buffers.glyphVertex; - this.buffers.glyphElement = buffers.glyphElement; - this.buffers.iconVertex = buffers.iconVertex; - this.buffers.iconElement = buffers.iconElement; - this.buffers.collisionBoxVertex = buffers.collisionBoxVertex; - - for (var id in data.elementGroups) { - this.elementGroups[id] = data.elementGroups[id]; - } - }, - - /** - * Make sure that this tile doesn't own any data within a given - * painter, so that it doesn't consume any memory or maintain - * any references to the painter. - * @param {Object} painter gl painter object - * @returns {undefined} - * @private - */ - unloadVectorData: function(painter) { - this.loaded = false; - - for (var b in this.buffers) { - if (this.buffers[b]) this.buffers[b].destroy(painter.gl); - } - - this.elementGroups = null; - this.buffers = null; - }, - - redoPlacement: function(source) { - if (!this.loaded || this.redoingPlacement) { - this.redoWhenDone = true; - return; - } + // calculate quat * vec + ix = qw * x + qy * z - qz * y, + iy = qw * y + qz * x - qx * z, + iz = qw * z + qx * y - qy * x, + iw = -qx * x - qy * y - qz * z; - this.redoingPlacement = true; + // calculate result * inverse quat + out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; + out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; + out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; + return out; +}; - source.dispatcher.send('redo placement', { - uid: this.uid, - source: source.id, - angle: source.map.transform.angle, - pitch: source.map.transform.pitch, - collisionDebug: source.map.collisionDebug - }, done.bind(this), this.workerID); +/** + * Rotate a 3D vector around the x-axis + * @param {vec3} out The receiving vec3 + * @param {vec3} a The vec3 point to rotate + * @param {vec3} b The origin of the rotation + * @param {Number} c The angle of rotation + * @returns {vec3} out + */ +vec3.rotateX = function(out, a, b, c){ + var p = [], r=[]; + //Translate point to the origin + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; - function done(_, data) { - this.reloadSymbolData(data, source.map.painter); - source.fire('tile.load', {tile: this}); + //perform rotation + r[0] = p[0]; + r[1] = p[1]*Math.cos(c) - p[2]*Math.sin(c); + r[2] = p[1]*Math.sin(c) + p[2]*Math.cos(c); - this.redoingPlacement = false; - if (this.redoWhenDone) { - this.redoPlacement(source); - this.redoWhenDone = false; - } - } - }, + //translate to correct position + out[0] = r[0] + b[0]; + out[1] = r[1] + b[1]; + out[2] = r[2] + b[2]; - getElementGroups: function(layer, shaderName) { - return this.elementGroups && this.elementGroups[layer.ref || layer.id] && this.elementGroups[layer.ref || layer.id][shaderName]; - } + return out; }; -function unserializeBuffers(input) { - var output = {}; - for (var k in input) { - output[k] = new Buffer(input[k]); - } - return output; -} - -},{"../data/buffer":17,"../util/util":113}],50:[function(require,module,exports){ -'use strict'; +/** + * Rotate a 3D vector around the y-axis + * @param {vec3} out The receiving vec3 + * @param {vec3} a The vec3 point to rotate + * @param {vec3} b The origin of the rotation + * @param {Number} c The angle of rotation + * @returns {vec3} out + */ +vec3.rotateY = function(out, a, b, c){ + var p = [], r=[]; + //Translate point to the origin + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; + + //perform rotation + r[0] = p[2]*Math.sin(c) + p[0]*Math.cos(c); + r[1] = p[1]; + r[2] = p[2]*Math.cos(c) - p[0]*Math.sin(c); + + //translate to correct position + out[0] = r[0] + b[0]; + out[1] = r[1] + b[1]; + out[2] = r[2] + b[2]; + + return out; +}; -var assert = require('assert'); -var Coordinate = require('../geo/coordinate'); +/** + * Rotate a 3D vector around the z-axis + * @param {vec3} out The receiving vec3 + * @param {vec3} a The vec3 point to rotate + * @param {vec3} b The origin of the rotation + * @param {Number} c The angle of rotation + * @returns {vec3} out + */ +vec3.rotateZ = function(out, a, b, c){ + var p = [], r=[]; + //Translate point to the origin + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; + + //perform rotation + r[0] = p[0]*Math.cos(c) - p[1]*Math.sin(c); + r[1] = p[0]*Math.sin(c) + p[1]*Math.cos(c); + r[2] = p[2]; + + //translate to correct position + out[0] = r[0] + b[0]; + out[1] = r[1] + b[1]; + out[2] = r[2] + b[2]; + + return out; +}; -module.exports = TileCoord; +/** + * Perform some operation over an array of vec3s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ +vec3.forEach = (function() { + var vec = vec3.create(); -function TileCoord(z, x, y, w) { - assert(!isNaN(z) && z >= 0 && z % 1 === 0); - assert(!isNaN(x) && x >= 0 && x % 1 === 0); - assert(!isNaN(y) && y >= 0 && y % 1 === 0); + return function(a, stride, offset, count, fn, arg) { + var i, l; + if(!stride) { + stride = 3; + } - if (isNaN(w)) w = 0; + if(!offset) { + offset = 0; + } + + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; + } - this.z = +z; - this.x = +x; - this.y = +y; - this.w = +w; + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; + } + + return a; + }; +})(); - // calculate id - w *= 2; - if (w < 0) w = w * -1 - 1; - var dim = 1 << this.z; - this.id = ((dim * dim * w + dim * this.y + this.x) * 32) + this.z; -} +/** + * Get the angle between two 3D vectors + * @param {vec3} a The first operand + * @param {vec3} b The second operand + * @returns {Number} The angle in radians + */ +vec3.angle = function(a, b) { + + var tempA = vec3.fromValues(a[0], a[1], a[2]); + var tempB = vec3.fromValues(b[0], b[1], b[2]); + + vec3.normalize(tempA, tempA); + vec3.normalize(tempB, tempB); + + var cosine = vec3.dot(tempA, tempB); -TileCoord.prototype.toString = function() { - return this.z + "/" + this.x + "/" + this.y; + if(cosine > 1.0){ + return 0; + } else { + return Math.acos(cosine); + } }; -TileCoord.prototype.toCoordinate = function() { - var zoom = this.z; - var tileScale = Math.pow(2, zoom); - var row = this.y; - var column = this.x + tileScale * this.w; - return new Coordinate(column, row, zoom); +/** + * Returns a string representation of a vector + * + * @param {vec3} vec vector to represent as a string + * @returns {String} string representation of the vector + */ +vec3.str = function (a) { + return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')'; }; -// Parse a packed integer id into a TileCoord object -TileCoord.fromID = function(id) { - var z = id % 32, dim = 1 << z; - var xy = ((id - z) / 32); - var x = xy % dim, y = ((xy - x) / dim) % dim; - var w = Math.floor(xy / (dim * dim)); - if (w % 2 !== 0) w = w * -1 - 1; - w /= 2; - return new TileCoord(z, x, y, w); +/** + * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===) + * + * @param {vec3} a The first vector. + * @param {vec3} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ +vec3.exactEquals = function (a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2]; }; -// given a list of urls, choose a url template and return a tile URL -TileCoord.prototype.url = function(urls, sourceMaxZoom) { - return urls[(this.x + this.y) % urls.length] - .replace('{prefix}', (this.x % 16).toString(16) + (this.y % 16).toString(16)) - .replace('{z}', Math.min(this.z, sourceMaxZoom || this.z)) - .replace('{x}', this.x) - .replace('{y}', this.y); +/** + * Returns whether or not the vectors have approximately the same elements in the same position. + * + * @param {vec3} a The first vector. + * @param {vec3} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ +vec3.equals = function (a, b) { + var a0 = a[0], a1 = a[1], a2 = a[2]; + var b0 = b[0], b1 = b[1], b2 = b[2]; + return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && + Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) && + Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2))); }; -// Return the coordinate of the parent tile -TileCoord.prototype.parent = function(sourceMaxZoom) { - if (this.z === 0) return null; - - // the id represents an overscaled tile, return the same coordinates with a lower z - if (this.z > sourceMaxZoom) { - return new TileCoord(this.z - 1, this.x, this.y, this.w); - } - - return new TileCoord(this.z - 1, Math.floor(this.x / 2), Math.floor(this.y / 2), this.w); -}; +module.exports = vec3; -TileCoord.prototype.wrapped = function() { - return new TileCoord(this.z, this.x, this.y, 0); -}; +},{"./common.js":30}],38:[function(require,module,exports){ +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. -// Return the coordinates of the tile's children -TileCoord.prototype.children = function(sourceMaxZoom) { +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: - if (this.z >= sourceMaxZoom) { - // return a single tile coord representing a an overscaled tile - return [new TileCoord(this.z + 1, this.x, this.y, this.w)]; - } +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - var z = this.z + 1; - var x = this.x * 2; - var y = this.y * 2; - return [ - new TileCoord(z, x, y, this.w), - new TileCoord(z, x + 1, y, this.w), - new TileCoord(z, x, y + 1, this.w), - new TileCoord(z, x + 1, y + 1, this.w) - ]; -}; +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. */ -// Taken from polymaps src/Layer.js -// https://github.com/simplegeo/polymaps/blob/master/src/Layer.js#L333-L383 +var glMatrix = require("./common.js"); -function edge(a, b) { - if (a.row > b.row) { var t = a; a = b; b = t; } - return { - x0: a.column, - y0: a.row, - x1: b.column, - y1: b.row, - dx: b.column - a.column, - dy: b.row - a.row - }; -} +/** + * @class 4 Dimensional Vector + * @name vec4 + */ +var vec4 = {}; -function scanSpans(e0, e1, ymin, ymax, scanLine) { - var y0 = Math.max(ymin, Math.floor(e1.y0)); - var y1 = Math.min(ymax, Math.ceil(e1.y1)); +/** + * Creates a new, empty vec4 + * + * @returns {vec4} a new 4D vector + */ +vec4.create = function() { + var out = new glMatrix.ARRAY_TYPE(4); + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 0; + return out; +}; - // sort edges by x-coordinate - if ((e0.x0 === e1.x0 && e0.y0 === e1.y0) ? - (e0.x0 + e1.dy / e0.dy * e0.dx < e1.x1) : - (e0.x1 - e1.dy / e0.dy * e0.dx < e1.x0)) { - var t = e0; e0 = e1; e1 = t; - } +/** + * Creates a new vec4 initialized with values from an existing vector + * + * @param {vec4} a vector to clone + * @returns {vec4} a new 4D vector + */ +vec4.clone = function(a) { + var out = new glMatrix.ARRAY_TYPE(4); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +}; - // scan lines! - var m0 = e0.dx / e0.dy; - var m1 = e1.dx / e1.dy; - var d0 = e0.dx > 0; // use y + 1 to compute x0 - var d1 = e1.dx < 0; // use y + 1 to compute x1 - for (var y = y0; y < y1; y++) { - var x0 = m0 * Math.max(0, Math.min(e0.dy, y + d0 - e0.y0)) + e0.x0; - var x1 = m1 * Math.max(0, Math.min(e1.dy, y + d1 - e1.y0)) + e1.x0; - scanLine(Math.floor(x1), Math.ceil(x0), y); - } -} +/** + * Creates a new vec4 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {vec4} a new 4D vector + */ +vec4.fromValues = function(x, y, z, w) { + var out = new glMatrix.ARRAY_TYPE(4); + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = w; + return out; +}; -function scanTriangle(a, b, c, ymin, ymax, scanLine) { - var ab = edge(a, b), - bc = edge(b, c), - ca = edge(c, a); +/** + * Copy the values from one vec4 to another + * + * @param {vec4} out the receiving vector + * @param {vec4} a the source vector + * @returns {vec4} out + */ +vec4.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +}; - var t; +/** + * Set the components of a vec4 to the given values + * + * @param {vec4} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {vec4} out + */ +vec4.set = function(out, x, y, z, w) { + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = w; + return out; +}; - // sort edges by y-length - if (ab.dy > bc.dy) { t = ab; ab = bc; bc = t; } - if (ab.dy > ca.dy) { t = ab; ab = ca; ca = t; } - if (bc.dy > ca.dy) { t = bc; bc = ca; ca = t; } +/** + * Adds two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.add = function(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + return out; +}; - // scan span! scan span! - if (ab.dy) scanSpans(ca, ab, ymin, ymax, scanLine); - if (bc.dy) scanSpans(ca, bc, ymin, ymax, scanLine); -} +/** + * Subtracts vector b from vector a + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.subtract = function(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + return out; +}; -TileCoord.cover = function(z, bounds, actualZ) { - var tiles = 1 << z; - var t = {}; +/** + * Alias for {@link vec4.subtract} + * @function + */ +vec4.sub = vec4.subtract; - function scanLine(x0, x1, y) { - var x, wx, coord; - if (y >= 0 && y <= tiles) { - for (x = x0; x < x1; x++) { - wx = (x % tiles + tiles) % tiles; - coord = new TileCoord(actualZ, wx, y, Math.floor(x / tiles)); - t[coord.id] = coord; - } - } - } +/** + * Multiplies two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.multiply = function(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; + out[3] = a[3] * b[3]; + return out; +}; - // Divide the screen up in two triangles and scan each of them: - // +---/ - // | / | - // /---+ - scanTriangle(bounds[0], bounds[1], bounds[2], 0, tiles, scanLine); - scanTriangle(bounds[2], bounds[3], bounds[0], 0, tiles, scanLine); +/** + * Alias for {@link vec4.multiply} + * @function + */ +vec4.mul = vec4.multiply; - return Object.keys(t).map(function(id) { - return t[id]; - }); +/** + * Divides two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.divide = function(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + out[2] = a[2] / b[2]; + out[3] = a[3] / b[3]; + return out; }; -},{"../geo/coordinate":25,"assert":2}],51:[function(require,module,exports){ -'use strict'; - -var Tile = require('./tile'); -var TileCoord = require('./tile_coord'); -var Point = require('point-geometry'); -var Cache = require('../util/mru_cache'); -var util = require('../util/util'); -var EXTENT = require('../data/buffer').EXTENT; +/** + * Alias for {@link vec4.divide} + * @function + */ +vec4.div = vec4.divide; -module.exports = TilePyramid; +/** + * Math.ceil the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to ceil + * @returns {vec4} out + */ +vec4.ceil = function (out, a) { + out[0] = Math.ceil(a[0]); + out[1] = Math.ceil(a[1]); + out[2] = Math.ceil(a[2]); + out[3] = Math.ceil(a[3]); + return out; +}; /** - * A tile pyramid is a specialized cache and datastructure - * that contains tiles. It's used by sources to manage their - * data. + * Math.floor the components of a vec4 * - * @param {Object} options - * @param {number} options.tileSize - * @param {number} options.minzoom - * @param {number} options.maxzoom - * @private + * @param {vec4} out the receiving vector + * @param {vec4} a vector to floor + * @returns {vec4} out */ -function TilePyramid(options) { - this.tileSize = options.tileSize; - this.minzoom = options.minzoom; - this.maxzoom = options.maxzoom; - this.roundZoom = options.roundZoom; - this.reparseOverscaled = options.reparseOverscaled; +vec4.floor = function (out, a) { + out[0] = Math.floor(a[0]); + out[1] = Math.floor(a[1]); + out[2] = Math.floor(a[2]); + out[3] = Math.floor(a[3]); + return out; +}; - this._load = options.load; - this._abort = options.abort; - this._unload = options.unload; - this._add = options.add; - this._remove = options.remove; - this._redoPlacement = options.redoPlacement; +/** + * Returns the minimum of two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.min = function(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + out[2] = Math.min(a[2], b[2]); + out[3] = Math.min(a[3], b[3]); + return out; +}; - this._tiles = {}; - this._cache = new Cache(options.cacheSize, function(tile) { return this._unload(tile); }.bind(this)); +/** + * Returns the maximum of two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.max = function(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + out[2] = Math.max(a[2], b[2]); + out[3] = Math.max(a[3], b[3]); + return out; +}; - this._filterRendered = this._filterRendered.bind(this); -} +/** + * Math.round the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to round + * @returns {vec4} out + */ +vec4.round = function (out, a) { + out[0] = Math.round(a[0]); + out[1] = Math.round(a[1]); + out[2] = Math.round(a[2]); + out[3] = Math.round(a[3]); + return out; +}; -TilePyramid.prototype = { - /** - * Confirm that every tracked tile is loaded. - * @returns {boolean} whether all tiles are loaded. - * @private - */ - loaded: function() { - for (var t in this._tiles) { - if (!this._tiles[t].loaded && !this._tiles[t].errored) - return false; - } - return true; - }, - - /** - * Return all tile ids ordered with z-order, and cast to numbers - * @returns {Array} ids - * @private - */ - orderedIDs: function() { - return Object.keys(this._tiles).map(Number).sort(compareKeyZoom); - }, - - renderedIDs: function() { - return this.orderedIDs().filter(this._filterRendered); - }, - - _filterRendered: function(id) { - return this._tiles[id].loaded && !this._coveredTiles[id]; - }, - - reload: function() { - this._cache.reset(); - for (var i in this._tiles) { - this._load(this._tiles[i]); - } - }, +/** + * Scales a vec4 by a scalar number + * + * @param {vec4} out the receiving vector + * @param {vec4} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec4} out + */ +vec4.scale = function(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + return out; +}; - /** - * Get a specific tile by id - * @param {string|number} id tile id - * @returns {Object} tile - * @private - */ - getTile: function(id) { - return this._tiles[id]; - }, +/** + * Adds two vec4's after scaling the second operand by a scalar value + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec4} out + */ +vec4.scaleAndAdd = function(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + out[2] = a[2] + (b[2] * scale); + out[3] = a[3] + (b[3] * scale); + return out; +}; - /** - * get the zoom level adjusted for the difference in map and source tilesizes - * @param {Object} transform - * @returns {number} zoom level - * @private - */ - getZoom: function(transform) { - return transform.zoom + Math.log(transform.tileSize / this.tileSize) / Math.LN2; - }, - - /** - * Return a zoom level that will cover all tiles in a given transform - * @param {Object} transform - * @returns {number} zoom level - * @private - */ - coveringZoomLevel: function(transform) { - return (this.roundZoom ? Math.round : Math.floor)(this.getZoom(transform)); - }, - - /** - * Given a transform, return all coordinates that could cover that - * transform for a covering zoom level. - * @param {Object} transform - * @returns {Array} tiles - * @private - */ - coveringTiles: function(transform) { - var z = this.coveringZoomLevel(transform); - var actualZ = z; +/** + * Calculates the euclidian distance between two vec4's + * + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {Number} distance between a and b + */ +vec4.distance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1], + z = b[2] - a[2], + w = b[3] - a[3]; + return Math.sqrt(x*x + y*y + z*z + w*w); +}; - if (z < this.minzoom) return []; - if (z > this.maxzoom) z = this.maxzoom; +/** + * Alias for {@link vec4.distance} + * @function + */ +vec4.dist = vec4.distance; - var tr = transform, - tileCenter = tr.locationCoordinate(tr.center)._zoomTo(z), - centerPoint = new Point(tileCenter.column - 0.5, tileCenter.row - 0.5); +/** + * Calculates the squared euclidian distance between two vec4's + * + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {Number} squared distance between a and b + */ +vec4.squaredDistance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1], + z = b[2] - a[2], + w = b[3] - a[3]; + return x*x + y*y + z*z + w*w; +}; - return TileCoord.cover(z, [ - tr.pointCoordinate(new Point(0, 0))._zoomTo(z), - tr.pointCoordinate(new Point(tr.width, 0))._zoomTo(z), - tr.pointCoordinate(new Point(tr.width, tr.height))._zoomTo(z), - tr.pointCoordinate(new Point(0, tr.height))._zoomTo(z) - ], this.reparseOverscaled ? actualZ : z).sort(function(a, b) { - return centerPoint.dist(a) - centerPoint.dist(b); - }); - }, +/** + * Alias for {@link vec4.squaredDistance} + * @function + */ +vec4.sqrDist = vec4.squaredDistance; - /** - * Recursively find children of the given tile (up to maxCoveringZoom) that are already loaded; - * adds found tiles to retain object; returns true if any child is found. - * - * @param {Coordinate} coord - * @param {number} maxCoveringZoom - * @param {boolean} retain - * @returns {boolean} whether the operation was complete - * @private - */ - findLoadedChildren: function(coord, maxCoveringZoom, retain) { - var found = false; +/** + * Calculates the length of a vec4 + * + * @param {vec4} a vector to calculate length of + * @returns {Number} length of a + */ +vec4.length = function (a) { + var x = a[0], + y = a[1], + z = a[2], + w = a[3]; + return Math.sqrt(x*x + y*y + z*z + w*w); +}; - for (var id in this._tiles) { - var tile = this._tiles[id]; +/** + * Alias for {@link vec4.length} + * @function + */ +vec4.len = vec4.length; - // only consider loaded tiles on higher zoom levels (up to maxCoveringZoom) - if (retain[id] || !tile.loaded || tile.coord.z <= coord.z || tile.coord.z > maxCoveringZoom) continue; +/** + * Calculates the squared length of a vec4 + * + * @param {vec4} a vector to calculate squared length of + * @returns {Number} squared length of a + */ +vec4.squaredLength = function (a) { + var x = a[0], + y = a[1], + z = a[2], + w = a[3]; + return x*x + y*y + z*z + w*w; +}; - // disregard tiles that are not descendants of the given tile coordinate - var z2 = Math.pow(2, Math.min(tile.coord.z, this.maxzoom) - Math.min(coord.z, this.maxzoom)); - if (Math.floor(tile.coord.x / z2) !== coord.x || - Math.floor(tile.coord.y / z2) !== coord.y) - continue; +/** + * Alias for {@link vec4.squaredLength} + * @function + */ +vec4.sqrLen = vec4.squaredLength; - // found loaded child - retain[id] = true; - found = true; +/** + * Negates the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to negate + * @returns {vec4} out + */ +vec4.negate = function(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = -a[3]; + return out; +}; - // loop through parents; retain the topmost loaded one if found - while (tile && tile.coord.z - 1 > coord.z) { - var parentId = tile.coord.parent(this.maxzoom).id; - tile = this._tiles[parentId]; +/** + * Returns the inverse of the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to invert + * @returns {vec4} out + */ +vec4.inverse = function(out, a) { + out[0] = 1.0 / a[0]; + out[1] = 1.0 / a[1]; + out[2] = 1.0 / a[2]; + out[3] = 1.0 / a[3]; + return out; +}; - if (tile && tile.loaded) { - delete retain[id]; - retain[parentId] = true; - } - } - } - return found; - }, +/** + * Normalize a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to normalize + * @returns {vec4} out + */ +vec4.normalize = function(out, a) { + var x = a[0], + y = a[1], + z = a[2], + w = a[3]; + var len = x*x + y*y + z*z + w*w; + if (len > 0) { + len = 1 / Math.sqrt(len); + out[0] = x * len; + out[1] = y * len; + out[2] = z * len; + out[3] = w * len; + } + return out; +}; - /** - * Find a loaded parent of the given tile (up to minCoveringZoom); - * adds the found tile to retain object and returns the tile if found - * - * @param {Coordinate} coord - * @param {number} minCoveringZoom - * @param {boolean} retain - * @returns {Tile} tile object - * @private - */ - findLoadedParent: function(coord, minCoveringZoom, retain) { - for (var z = coord.z - 1; z >= minCoveringZoom; z--) { - coord = coord.parent(this.maxzoom); - var tile = this._tiles[coord.id]; - if (tile && tile.loaded) { - retain[coord.id] = true; - return tile; - } - } - }, +/** + * Calculates the dot product of two vec4's + * + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {Number} dot product of a and b + */ +vec4.dot = function (a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; +}; - /** - * Removes tiles that are outside the viewport and adds new tiles that - * are inside the viewport. - * @private - */ - update: function(used, transform, fadeDuration) { - var i; - var coord; - var tile; +/** + * Performs a linear interpolation between two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec4} out + */ +vec4.lerp = function (out, a, b, t) { + var ax = a[0], + ay = a[1], + az = a[2], + aw = a[3]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + out[2] = az + t * (b[2] - az); + out[3] = aw + t * (b[3] - aw); + return out; +}; - // Determine the overzooming/underzooming amounts. - var zoom = (this.roundZoom ? Math.round : Math.floor)(this.getZoom(transform)); - var minCoveringZoom = Math.max(zoom - 10, this.minzoom); - var maxCoveringZoom = Math.max(zoom + 3, this.minzoom); +/** + * Generates a random vector with the given scale + * + * @param {vec4} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec4} out + */ +vec4.random = function (out, scale) { + scale = scale || 1.0; - // Retain is a list of tiles that we shouldn't delete, even if they are not - // the most ideal tile for the current viewport. This may include tiles like - // parent or child tiles that are *already* loaded. - var retain = {}; - var now = new Date().getTime(); + //TODO: This is a pretty awful way of doing this. Find something better. + out[0] = glMatrix.RANDOM(); + out[1] = glMatrix.RANDOM(); + out[2] = glMatrix.RANDOM(); + out[3] = glMatrix.RANDOM(); + vec4.normalize(out, out); + vec4.scale(out, out, scale); + return out; +}; - // Covered is a list of retained tiles who's areas are full covered by other, - // better, retained tiles. They are not drawn separately. - this._coveredTiles = {}; - - var required = used ? this.coveringTiles(transform) : []; - for (i = 0; i < required.length; i++) { - coord = required[i]; - tile = this.addTile(coord); +/** + * Transforms the vec4 with a mat4. + * + * @param {vec4} out the receiving vector + * @param {vec4} a the vector to transform + * @param {mat4} m matrix to transform with + * @returns {vec4} out + */ +vec4.transformMat4 = function(out, a, m) { + var x = a[0], y = a[1], z = a[2], w = a[3]; + out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w; + out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w; + out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w; + out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w; + return out; +}; - retain[coord.id] = true; +/** + * Transforms the vec4 with a quat + * + * @param {vec4} out the receiving vector + * @param {vec4} a the vector to transform + * @param {quat} q quaternion to transform with + * @returns {vec4} out + */ +vec4.transformQuat = function(out, a, q) { + var x = a[0], y = a[1], z = a[2], + qx = q[0], qy = q[1], qz = q[2], qw = q[3], - if (tile.loaded) - continue; + // calculate quat * vec + ix = qw * x + qy * z - qz * y, + iy = qw * y + qz * x - qx * z, + iz = qw * z + qx * y - qy * x, + iw = -qx * x - qy * y - qz * z; - // The tile we require is not yet loaded. - // Retain child or parent tiles that cover the same area. - if (!this.findLoadedChildren(coord, maxCoveringZoom, retain)) { - this.findLoadedParent(coord, minCoveringZoom, retain); - } - } + // calculate result * inverse quat + out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; + out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; + out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; + out[3] = a[3]; + return out; +}; - var parentsForFading = {}; +/** + * Perform some operation over an array of vec4s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ +vec4.forEach = (function() { + var vec = vec4.create(); - var ids = Object.keys(retain); - for (var k = 0; k < ids.length; k++) { - var id = ids[k]; - coord = TileCoord.fromID(id); - tile = this._tiles[id]; - if (tile && tile.timeAdded > now - (fadeDuration || 0)) { - // This tile is still fading in. Find tiles to cross-fade with it. - if (this.findLoadedChildren(coord, maxCoveringZoom, retain)) { - retain[id] = true; - } - this.findLoadedParent(coord, minCoveringZoom, parentsForFading); - } + return function(a, stride, offset, count, fn, arg) { + var i, l; + if(!stride) { + stride = 4; } - var fadedParent; - for (fadedParent in parentsForFading) { - if (!retain[fadedParent]) { - // If a tile is only needed for fading, mark it as covered so that it isn't rendered on it's own. - this._coveredTiles[fadedParent] = true; - } + if(!offset) { + offset = 0; } - for (fadedParent in parentsForFading) { - retain[fadedParent] = true; + + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; } - // Remove the tiles we don't need anymore. - var remove = util.keysDifference(this._tiles, retain); - for (i = 0; i < remove.length; i++) { - this.removeTile(+remove[i]); + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3]; } + + return a; + }; +})(); - this.transform = transform; - }, - - /** - * Add a tile, given its coordinate, to the pyramid. - * @param {Coordinate} coord - * @returns {Coordinate} the coordinate. - * @private - */ - addTile: function(coord) { - var tile = this._tiles[coord.id]; - if (tile) - return tile; +/** + * Returns a string representation of a vector + * + * @param {vec4} vec vector to represent as a string + * @returns {String} string representation of the vector + */ +vec4.str = function (a) { + return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; +}; - var wrapped = coord.wrapped(); - tile = this._tiles[wrapped.id]; +/** + * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===) + * + * @param {vec4} a The first vector. + * @param {vec4} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ +vec4.exactEquals = function (a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]; +}; - if (!tile) { - tile = this._cache.get(wrapped.id); - if (tile && this._redoPlacement) { - this._redoPlacement(tile); - } - } +/** + * Returns whether or not the vectors have approximately the same elements in the same position. + * + * @param {vec4} a The first vector. + * @param {vec4} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ +vec4.equals = function (a, b) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; + var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && + Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) && + Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) && + Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3))); +}; - if (!tile) { - var zoom = coord.z; - var overscaling = zoom > this.maxzoom ? Math.pow(2, zoom - this.maxzoom) : 1; - tile = new Tile(wrapped, this.tileSize * overscaling, this.maxzoom); - this._load(tile); - } +module.exports = vec4; - tile.uses++; - this._tiles[coord.id] = tile; - this._add(tile, coord); +},{"./common.js":30}],39:[function(require,module,exports){ +'use strict'; - return tile; - }, +module.exports = GridIndex; - /** - * Remove a tile, given its id, from the pyramid - * @param {string|number} id tile id - * @returns {undefined} nothing - * @private - */ - removeTile: function(id) { - var tile = this._tiles[id]; - if (!tile) - return; +var NUM_PARAMS = 3; - tile.uses--; - delete this._tiles[id]; - this._remove(tile); +function GridIndex(extent, n, padding) { + var cells = this.cells = []; - if (tile.uses > 0) - return; + if (extent instanceof ArrayBuffer) { + this.arrayBuffer = extent; + var array = new Int32Array(this.arrayBuffer); + extent = array[0]; + n = array[1]; + padding = array[2]; - if (tile.loaded) { - this._cache.add(tile.coord.wrapped().id, tile); - } else { - this._abort(tile); - this._unload(tile); + this.d = n + 2 * padding; + for (var k = 0; k < this.d * this.d; k++) { + var start = array[NUM_PARAMS + k]; + var end = array[NUM_PARAMS + k + 1]; + cells.push(start === end ? + null : + array.subarray(start, end)); } - }, + var keysOffset = array[NUM_PARAMS + cells.length]; + var bboxesOffset = array[NUM_PARAMS + cells.length + 1]; + this.keys = array.subarray(keysOffset, bboxesOffset); + this.bboxes = array.subarray(bboxesOffset); - /** - * Remove all tiles from this pyramid - * @private - */ - clearTiles: function() { - for (var id in this._tiles) - this.removeTile(id); - this._cache.reset(); - }, + this.insert = this._insertReadonly; - /** - * For a given coordinate, search through our current tiles and attempt - * to find a tile at that point - * @param {Coordinate} coord - * @returns {Object} tile - * @private - */ - tileAt: function(coord) { - var ids = this.orderedIDs(); - for (var i = 0; i < ids.length; i++) { - var tile = this._tiles[ids[i]]; - var pos = tile.positionAt(coord); - if (pos && pos.x >= 0 && pos.x < EXTENT && pos.y >= 0 && pos.y < EXTENT) { - // The click is within the viewport. There is only ever one tile in - // a layer that has this property. - return { - tile: tile, - x: pos.x, - y: pos.y, - scale: this.transform.worldSize / Math.pow(2, tile.coord.z) - }; - } + } else { + this.d = n + 2 * padding; + for (var i = 0; i < this.d * this.d; i++) { + cells.push([]); } - }, + this.keys = []; + this.bboxes = []; + } - /** - * Search through our current tiles and attempt to find the tiles that - * cover the given bounds. - * @param {Array} bounds [minxminy, maxxmaxy] coordinates of the corners of bounding rectangle - * @returns {Array} result items have {tile, minX, maxX, minY, maxY}, where min/max bounding values are the given bounds transformed in into the coordinate space of this tile. - * @private - */ - tilesIn: function(bounds) { - var result = []; - var ids = this.orderedIDs(); + this.n = n; + this.extent = extent; + this.padding = padding; + this.scale = n / extent; + this.uid = 0; - for (var i = 0; i < ids.length; i++) { - var tile = this._tiles[ids[i]]; - var tileSpaceBounds = [ - tile.positionAt(bounds[0]), - tile.positionAt(bounds[1]) - ]; - if (tileSpaceBounds[0].x < EXTENT && tileSpaceBounds[0].y < EXTENT && - tileSpaceBounds[1].x >= 0 && tileSpaceBounds[1].y >= 0) { - result.push({ - tile: tile, - minX: tileSpaceBounds[0].x, - maxX: tileSpaceBounds[1].x, - minY: tileSpaceBounds[0].y, - maxY: tileSpaceBounds[1].y - }); - } - } + var p = (padding / n) * extent; + this.min = -p; + this.max = extent + p; +} - return result; - } + +GridIndex.prototype.insert = function(key, x1, y1, x2, y2) { + this._forEachCell(x1, y1, x2, y2, this._insertCell, this.uid++); + this.keys.push(key); + this.bboxes.push(x1); + this.bboxes.push(y1); + this.bboxes.push(x2); + this.bboxes.push(y2); }; -function compareKeyZoom(a, b) { - return (b % 32) - (a % 32); -} +GridIndex.prototype._insertReadonly = function() { + throw 'Cannot insert into a GridIndex created from an ArrayBuffer.'; +}; -},{"../data/buffer":17,"../util/mru_cache":111,"../util/util":113,"./tile":49,"./tile_coord":50,"point-geometry":162}],52:[function(require,module,exports){ -'use strict'; +GridIndex.prototype._insertCell = function(x1, y1, x2, y2, cellIndex, uid) { + this.cells[cellIndex].push(uid); +}; -var util = require('../util/util'); -var Evented = require('../util/evented'); -var Source = require('./source'); -var normalizeURL = require('../util/mapbox').normalizeTileURL; +GridIndex.prototype.query = function(x1, y1, x2, y2) { + var min = this.min; + var max = this.max; + if (x1 <= min && y1 <= min && max <= x2 && max <= y2) { + // We use `Array#slice` because `this.keys` may be a `Int32Array` and + // some browsers (Safari and IE) do not support `TypedArray#slice` + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/slice#Browser_compatibility + return Array.prototype.slice.call(this.keys); -module.exports = VectorTileSource; + } else { + var result = []; + var seenUids = {}; + this._forEachCell(x1, y1, x2, y2, this._queryCell, result, seenUids); + return result; + } +}; -function VectorTileSource(options) { - util.extend(this, util.pick(options, ['url', 'tileSize'])); - this._options = util.extend({ type: 'vector' }, options); +GridIndex.prototype._queryCell = function(x1, y1, x2, y2, cellIndex, result, seenUids) { + var cell = this.cells[cellIndex]; + if (cell !== null) { + var keys = this.keys; + var bboxes = this.bboxes; + for (var u = 0; u < cell.length; u++) { + var uid = cell[u]; + if (seenUids[uid] === undefined) { + var offset = uid * 4; + if ((x1 <= bboxes[offset + 2]) && + (y1 <= bboxes[offset + 3]) && + (x2 >= bboxes[offset + 0]) && + (y2 >= bboxes[offset + 1])) { + seenUids[uid] = true; + result.push(keys[uid]); + } else { + seenUids[uid] = false; + } + } + } + } +}; - if (this.tileSize !== 512) { - throw new Error('vector tile sources must have a tileSize of 512'); +GridIndex.prototype._forEachCell = function(x1, y1, x2, y2, fn, arg1, arg2) { + var cx1 = this._convertToCellCoord(x1); + var cy1 = this._convertToCellCoord(y1); + var cx2 = this._convertToCellCoord(x2); + var cy2 = this._convertToCellCoord(y2); + for (var x = cx1; x <= cx2; x++) { + for (var y = cy1; y <= cy2; y++) { + var cellIndex = this.d * y + x; + if (fn.call(this, x1, y1, x2, y2, cellIndex, arg1, arg2)) return; + } } +}; - Source._loadTileJSON.call(this, options); -} +GridIndex.prototype._convertToCellCoord = function(x) { + return Math.max(0, Math.min(this.d - 1, Math.floor(x * this.scale) + this.padding)); +}; -VectorTileSource.prototype = util.inherit(Evented, { - minzoom: 0, - maxzoom: 22, - tileSize: 512, - reparseOverscaled: true, - _loaded: false, - isTileClipped: true, +GridIndex.prototype.toArrayBuffer = function() { + if (this.arrayBuffer) return this.arrayBuffer; - onAdd: function(map) { - this.map = map; - }, + var cells = this.cells; - loaded: function() { - return this._pyramid && this._pyramid.loaded(); - }, + var metadataLength = NUM_PARAMS + this.cells.length + 1 + 1; + var totalCellLength = 0; + for (var i = 0; i < this.cells.length; i++) { + totalCellLength += this.cells[i].length; + } - update: function(transform) { - if (this._pyramid) { - this._pyramid.update(this.used, transform); - } - }, + var array = new Int32Array(metadataLength + totalCellLength + this.keys.length + this.bboxes.length); + array[0] = this.extent; + array[1] = this.n; + array[2] = this.padding; - reload: function() { - if (this._pyramid) { - this._pyramid.reload(); - } - }, + var offset = metadataLength; + for (var k = 0; k < cells.length; k++) { + var cell = cells[k]; + array[NUM_PARAMS + k] = offset; + array.set(cell, offset); + offset += cell.length; + } - serialize: function() { - return util.extend({}, this._options); - }, + array[NUM_PARAMS + cells.length] = offset; + array.set(this.keys, offset); + offset += this.keys.length; - getVisibleCoordinates: Source._getVisibleCoordinates, - getTile: Source._getTile, + array[NUM_PARAMS + cells.length + 1] = offset; + array.set(this.bboxes, offset); + offset += this.bboxes.length; - featuresAt: Source._vectorFeaturesAt, - featuresIn: Source._vectorFeaturesIn, + return array.buffer; +}; - _loadTile: function(tile) { - var overscaling = tile.coord.z > this.maxzoom ? Math.pow(2, tile.coord.z - this.maxzoom) : 1; - var params = { - url: normalizeURL(tile.coord.url(this.tiles, this.maxzoom), this.url), - uid: tile.uid, - coord: tile.coord, - zoom: tile.coord.z, - tileSize: this.tileSize * overscaling, - source: this.id, - overscaling: overscaling, - angle: this.map.transform.angle, - pitch: this.map.transform.pitch, - collisionDebug: this.map.collisionDebug - }; +},{}],40:[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] - if (tile.workerID) { - this.dispatcher.send('reload tile', params, this._tileLoaded.bind(this, tile), tile.workerID); - } else { - tile.workerID = this.dispatcher.send('load tile', params, this._tileLoaded.bind(this, tile)); - } - }, + i += d - _tileLoaded: function(tile, err, data) { - if (tile.aborted) - return; + e = s & ((1 << (-nBits)) - 1) + s >>= (-nBits) + nBits += eLen + for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} - if (err) { - this.fire('tile.error', {tile: tile, error: err}); - return; - } - - tile.loadVectorData(data); + m = e & ((1 << (-nBits)) - 1) + e >>= (-nBits) + nBits += mLen + for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} - if (tile.redoWhenDone) { - tile.redoWhenDone = false; - tile.redoPlacement(this); - } + 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) +} - this.fire('tile.load', {tile: tile}); - this.fire('tile.stats', data.bucketStats); - }, +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 - _abortTile: function(tile) { - tile.aborted = true; - this.dispatcher.send('abort tile', { uid: tile.uid, source: this.id }, null, tile.workerID); - }, + value = Math.abs(value) - _addTile: function(tile) { - this.fire('tile.add', {tile: tile}); - }, + 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 + } - _removeTile: function(tile) { - this.fire('tile.remove', {tile: tile}); - }, + 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 + } + } - _unloadTile: function(tile) { - tile.unloadVectorData(this.map.painter); - this.dispatcher.send('remove tile', { uid: tile.uid, source: this.id }, null, tile.workerID); - }, + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} - redoPlacement: Source.redoPlacement, + e = (e << mLen) | m + eLen += mLen + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} - _redoTilePlacement: function(tile) { - tile.redoPlacement(this); - } -}); + buffer[offset + i - d] |= s * 128 +} -},{"../util/evented":107,"../util/mapbox":110,"../util/util":113,"./source":48}],53:[function(require,module,exports){ +},{}],41:[function(require,module,exports){ 'use strict'; -var util = require('../util/util'); -var Tile = require('./tile'); -var LngLat = require('../geo/lng_lat'); -var Point = require('point-geometry'); -var Evented = require('../util/evented'); -var ajax = require('../util/ajax'); -var EXTENT = require('../data/buffer').EXTENT; - -module.exports = VideoSource; - -/** - * Create a Video data source instance given an options object - * @class VideoSource - * @param {Object} [options] - * @param {Array} options.urls An array of URLs to video files - * @param {Array} options.coordinates lng, lat coordinates in order clockwise starting at the top left: tl, tr, br, bl - * @example - * var sourceObj = new mapboxgl.VideoSource({ - * url: [ - * 'https://www.mapbox.com/videos/baltimore-smoke.mp4', - * 'https://www.mapbox.com/videos/baltimore-smoke.webm' - * ], - * coordinates: [ - * [-76.54335737228394, 39.18579907229748], - * [-76.52803659439087, 39.1838364847587], - * [-76.5295386314392, 39.17683392507606], - * [-76.54520273208618, 39.17876344106642] - * ] - * }); - * map.addSource('some id', sourceObj); // add - * map.removeSource('some id'); // remove - */ -function VideoSource(options) { - this.urls = options.urls; - this.coordinates = options.coordinates; +var sort = require('./sort'); +var range = require('./range'); +var within = require('./within'); - ajax.getVideo(options.urls, function(err, video) { - // @TODO handle errors via event. - if (err) return; +module.exports = kdbush; - this.video = video; - this.video.loop = true; +function kdbush(points, getX, getY, nodeSize, ArrayType) { + return new KDBush(points, getX, getY, nodeSize, ArrayType); +} - var loopID; +function KDBush(points, getX, getY, nodeSize, ArrayType) { + getX = getX || defaultGetX; + getY = getY || defaultGetY; + ArrayType = ArrayType || Array; - // start repainting when video starts playing - this.video.addEventListener('playing', function() { - loopID = this.map.style.animationLoop.set(Infinity); - this.map._rerender(); - }.bind(this)); + this.nodeSize = nodeSize || 64; + this.points = points; - // stop repainting when video stops - this.video.addEventListener('pause', function() { - this.map.style.animationLoop.cancel(loopID); - }.bind(this)); + this.ids = new ArrayType(points.length); + this.coords = new ArrayType(points.length * 2); - this._loaded = true; + for (var i = 0; i < points.length; i++) { + this.ids[i] = i; + this.coords[2 * i] = getX(points[i]); + this.coords[2 * i + 1] = getY(points[i]); + } - if (this.map) { - this.video.play(); - this.createTile(options.coordinates); - this.fire('change'); - } - }.bind(this)); + sort(this.ids, this.coords, this.nodeSize, 0, this.ids.length - 1, 0); } -VideoSource.prototype = util.inherit(Evented, /** @lends VideoSource.prototype */{ - roundZoom: true, - - /** - * Return the HTML video element. - * - * @returns {Object} - */ - getVideo: function() { - return this.video; - }, - - onAdd: function(map) { - this.map = map; - if (this.video) { - this.video.play(); - this.createTile(); - } +KDBush.prototype = { + range: function (minX, minY, maxX, maxY) { + return range(this.ids, this.coords, minX, minY, maxX, maxY, this.nodeSize); }, - createTile: function(cornerGeoCoords) { - /* - * Calculate which mercator tile is suitable for rendering the video in - * and create a buffer with the corner coordinates. These coordinates - * may be outside the tile, because raster tiles aren't clipped when rendering. - */ - var map = this.map; - var cornerZ0Coords = cornerGeoCoords.map(function(coord) { - return map.transform.locationCoordinate(LngLat.convert(coord)).zoomTo(0); - }); - - var centerCoord = this.centerCoord = util.getCoordinatesCenter(cornerZ0Coords); - - var tileCoords = cornerZ0Coords.map(function(coord) { - var zoomedCoord = coord.zoomTo(centerCoord.zoom); - return new Point( - Math.round((zoomedCoord.column - centerCoord.column) * EXTENT), - Math.round((zoomedCoord.row - centerCoord.row) * EXTENT)); - }); - - var gl = map.painter.gl; - var maxInt16 = 32767; - var array = new Int16Array([ - tileCoords[0].x, tileCoords[0].y, 0, 0, - tileCoords[1].x, tileCoords[1].y, maxInt16, 0, - tileCoords[3].x, tileCoords[3].y, 0, maxInt16, - tileCoords[2].x, tileCoords[2].y, maxInt16, maxInt16 - ]); - - this.tile = new Tile(); - this.tile.buckets = {}; - - this.tile.boundsBuffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, this.tile.boundsBuffer); - gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW); - }, + within: function (x, y, r) { + return within(this.ids, this.coords, x, y, r, this.nodeSize); + } +}; - loaded: function() { - return this.video && this.video.readyState >= 2; - }, +function defaultGetX(p) { return p[0]; } +function defaultGetY(p) { return p[1]; } - update: function() { - // noop - }, +},{"./range":42,"./sort":43,"./within":44}],42:[function(require,module,exports){ +'use strict'; - reload: function() { - // noop - }, +module.exports = range; - prepare: function() { - if (!this._loaded) return; - if (this.video.readyState < 2) return; // not enough data for current position +function range(ids, coords, minX, minY, maxX, maxY, nodeSize) { + var stack = [0, ids.length - 1, 0]; + var result = []; + var x, y; - var gl = this.map.painter.gl; - if (!this.tile.texture) { - this.tile.texture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, this.tile.texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.video); - } else { - gl.bindTexture(gl.TEXTURE_2D, this.tile.texture); - gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.video); + while (stack.length) { + var axis = stack.pop(); + var right = stack.pop(); + var left = stack.pop(); + + if (right - left <= nodeSize) { + for (var i = left; i <= right; i++) { + x = coords[2 * i]; + y = coords[2 * i + 1]; + if (x >= minX && x <= maxX && y >= minY && y <= maxY) result.push(ids[i]); + } + continue; } - this._currentTime = this.video.currentTime; - }, - - getVisibleCoordinates: function() { - if (this.centerCoord) return [this.centerCoord]; - else return []; - }, + var m = Math.floor((left + right) / 2); - getTile: function() { - return this.tile; - }, + x = coords[2 * m]; + y = coords[2 * m + 1]; - featuresAt: function(point, params, callback) { - return callback(null, []); - }, + if (x >= minX && x <= maxX && y >= minY && y <= maxY) result.push(ids[m]); - featuresIn: function(bbox, params, callback) { - return callback(null, []); - }, + var nextAxis = (axis + 1) % 2; - serialize: function() { - return { - type: 'video', - urls: this.urls, - coordinates: this.coordinates - }; + if (axis === 0 ? minX <= x : minY <= y) { + stack.push(left); + stack.push(m - 1); + stack.push(nextAxis); + } + if (axis === 0 ? maxX >= x : maxY >= y) { + stack.push(m + 1); + stack.push(right); + stack.push(nextAxis); + } } -}); -},{"../data/buffer":17,"../geo/lng_lat":26,"../util/ajax":101,"../util/evented":107,"../util/util":113,"./tile":49,"point-geometry":162}],54:[function(require,module,exports){ + return result; +} + +},{}],43:[function(require,module,exports){ 'use strict'; -var Actor = require('../util/actor'); -var WorkerTile = require('./worker_tile'); -var util = require('../util/util'); -var ajax = require('../util/ajax'); -var vt = require('vector-tile'); -var Protobuf = require('pbf'); -var supercluster = require('supercluster'); +module.exports = sortKD; -var geojsonvt = require('geojson-vt'); -var GeoJSONWrapper = require('./geojson_wrapper'); +function sortKD(ids, coords, nodeSize, left, right, depth) { + if (right - left <= nodeSize) return; -module.exports = function(self) { - return new Worker(self); -}; + var m = Math.floor((left + right) / 2); -function Worker(self) { - this.self = self; - this.actor = new Actor(self, this); - this.loading = {}; + select(ids, coords, m, left, right, depth % 2); - this.loaded = {}; - this.layers = []; - this.geoJSONIndexes = {}; + sortKD(ids, coords, nodeSize, left, m - 1, depth + 1); + sortKD(ids, coords, nodeSize, m + 1, right, depth + 1); } -util.extend(Worker.prototype, { - 'set layers': function(layers) { - this.layers = layers; - }, - - 'load tile': function(params, callback) { - var source = params.source, - uid = params.uid; - - if (!this.loading[source]) - this.loading[source] = {}; +function select(ids, coords, k, left, right, inc) { + 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)); + select(ids, coords, k, newLeft, newRight, inc); + } - var tile = this.loading[source][uid] = new WorkerTile(params); + var t = coords[2 * k + inc]; + var i = left; + var j = right; - tile.xhr = ajax.getArrayBuffer(params.url, done.bind(this)); + swapItem(ids, coords, left, k); + if (coords[2 * right + inc] > t) swapItem(ids, coords, left, right); - function done(err, data) { - delete this.loading[source][uid]; + while (i < j) { + swapItem(ids, coords, i, j); + i++; + j--; + while (coords[2 * i + inc] < t) i++; + while (coords[2 * j + inc] > t) j--; + } - if (err) return callback(err); + if (coords[2 * left + inc] === t) swapItem(ids, coords, left, j); + else { + j++; + swapItem(ids, coords, j, right); + } - tile.data = new vt.VectorTile(new Protobuf(new Uint8Array(data))); - tile.parse(tile.data, this.layers, this.actor, callback); + if (j <= k) left = j + 1; + if (k <= j) right = j - 1; + } +} - this.loaded[source] = this.loaded[source] || {}; - this.loaded[source][uid] = tile; - } - }, +function swapItem(ids, coords, i, j) { + swap(ids, i, j); + swap(coords, 2 * i, 2 * j); + swap(coords, 2 * i + 1, 2 * j + 1); +} - 'reload tile': function(params, callback) { - var loaded = this.loaded[params.source], - uid = params.uid; - if (loaded && loaded[uid]) { - var tile = loaded[uid]; - tile.parse(tile.data, this.layers, this.actor, callback); - } - }, +function swap(arr, i, j) { + var tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; +} - 'abort tile': function(params) { - var loading = this.loading[params.source], - uid = params.uid; - if (loading && loading[uid]) { - loading[uid].xhr.abort(); - delete loading[uid]; - } - }, +},{}],44:[function(require,module,exports){ +'use strict'; - 'remove tile': function(params) { - var loaded = this.loaded[params.source], - uid = params.uid; - if (loaded && loaded[uid]) { - delete loaded[uid]; - } - }, +module.exports = within; - 'redo placement': function(params, callback) { - var loaded = this.loaded[params.source], - loading = this.loading[params.source], - uid = params.uid; +function within(ids, coords, qx, qy, r, nodeSize) { + var stack = [0, ids.length - 1, 0]; + var result = []; + var r2 = r * r; - if (loaded && loaded[uid]) { - var tile = loaded[uid]; - var result = tile.redoPlacement(params.angle, params.pitch, params.collisionDebug); + while (stack.length) { + var axis = stack.pop(); + var right = stack.pop(); + var left = stack.pop(); - if (result.result) { - callback(null, result.result, result.transferables); + if (right - left <= nodeSize) { + for (var i = left; i <= right; i++) { + if (sqDist(coords[2 * i], coords[2 * i + 1], qx, qy) <= r2) result.push(ids[i]); } - - } else if (loading && loading[uid]) { - loading[uid].angle = params.angle; + continue; } - }, - 'parse geojson': function(params, callback) { - var indexData = function(err, data) { - if (err) return callback(err); - if (typeof data != 'object') { - return callback(new Error("Input data is not a valid GeoJSON object.")); - } - try { - this.geoJSONIndexes[params.source] = params.cluster ? - supercluster(params.superclusterOptions).load(data.features) : - geojsonvt(data, params.geojsonVtOptions); - } catch (err) { - return callback(err); - } - callback(null); - }.bind(this); + var m = Math.floor((left + right) / 2); - // TODO accept params.url for urls instead + var x = coords[2 * m]; + var y = coords[2 * m + 1]; - // Not, because of same origin issues, urls must either include an - // explicit origin or absolute path. - // ie: /foo/bar.json or http://example.com/bar.json - // but not ../foo/bar.json - if (typeof params.data === 'string') { - ajax.getJSON(params.data, indexData); - } - else indexData(null, params.data); - }, + if (sqDist(x, y, qx, qy) <= r2) result.push(ids[m]); - 'load geojson tile': function(params, callback) { - var source = params.source, - coord = params.coord; + var nextAxis = (axis + 1) % 2; - if (!this.geoJSONIndexes[source]) return callback(null, null); // we couldn't load the file + if (axis === 0 ? qx - r <= x : qy - r <= y) { + stack.push(left); + stack.push(m - 1); + stack.push(nextAxis); + } + if (axis === 0 ? qx + r >= x : qy + r >= y) { + stack.push(m + 1); + stack.push(right); + stack.push(nextAxis); + } + } - // console.time('tile ' + coord.z + ' ' + coord.x + ' ' + coord.y); + return result; +} - var geoJSONTile = this.geoJSONIndexes[source].getTile(Math.min(coord.z, params.maxZoom), coord.x, coord.y); +function sqDist(ax, ay, bx, by) { + var dx = ax - bx; + var dy = ay - by; + return dx * dx + dy * dy; +} - // console.timeEnd('tile ' + coord.z + ' ' + coord.x + ' ' + coord.y); +},{}],45:[function(require,module,exports){ +'use strict'; - // if (!geoJSONTile) console.log('not found', this.geoJSONIndexes[source], coord); +function createFunction(parameters, defaultType) { + var fun; - if (!geoJSONTile) return callback(null, null); // nothing in the given tile + if (!isFunctionDefinition(parameters)) { + fun = function() { return parameters; }; + fun.isFeatureConstant = true; + fun.isZoomConstant = true; - var tile = new WorkerTile(params); - tile.parse(new GeoJSONWrapper(geoJSONTile.features), this.layers, this.actor, callback); - - this.loaded[source] = this.loaded[source] || {}; - this.loaded[source][params.uid] = tile; - }, - - 'query features': function(params, callback) { - var tile = this.loaded[params.source] && this.loaded[params.source][params.uid]; - if (tile) { - tile.featureTree.query(params, callback); + } else { + var zoomAndFeatureDependent = parameters.stops && typeof parameters.stops[0][0] === 'object'; + var featureDependent = zoomAndFeatureDependent || parameters.property !== undefined; + var zoomDependent = zoomAndFeatureDependent || !featureDependent; + var type = parameters.type || defaultType || 'exponential'; + + var innerFun; + if (type === 'exponential') { + innerFun = evaluateExponentialFunction; + } else if (type === 'interval') { + innerFun = evaluateIntervalFunction; + } else if (type === 'categorical') { + innerFun = evaluateCategoricalFunction; + } else if (type === 'identity') { + innerFun = evaluateIdentityFunction; } else { - callback(null, []); - } - } -}); - -},{"../util/actor":100,"../util/ajax":101,"../util/util":113,"./geojson_wrapper":45,"./worker_tile":55,"geojson-vt":118,"pbf":160,"supercluster":166,"vector-tile":168}],55:[function(require,module,exports){ -'use strict'; - -var FeatureTree = require('../data/feature_tree'); -var CollisionTile = require('../symbol/collision_tile'); -var Bucket = require('../data/bucket'); - -module.exports = WorkerTile; - -function WorkerTile(params) { - this.coord = params.coord; - this.uid = params.uid; - this.zoom = params.zoom; - this.tileSize = params.tileSize; - this.source = params.source; - this.overscaling = params.overscaling; - this.angle = params.angle; - this.pitch = params.pitch; - this.collisionDebug = params.collisionDebug; -} - -WorkerTile.prototype.parse = function(data, layers, actor, callback) { - - this.status = 'parsing'; - - this.featureTree = new FeatureTree(this.coord, this.overscaling); - - var stats = { _total: 0 }; - - var tile = this, - buffers = {}, - bucketsById = {}, - bucketsBySourceLayer = {}, - i, layer, sourceLayerId, bucket; - - // Map non-ref layers to buckets. - for (i = 0; i < layers.length; i++) { - layer = layers[i]; - - if (layer.source !== this.source) continue; - if (layer.ref) continue; - if (layer.minzoom && this.zoom < layer.minzoom) continue; - if (layer.maxzoom && this.zoom >= layer.maxzoom) continue; - if (layer.layout && layer.layout.visibility === 'none') continue; - - bucket = Bucket.create({ - layer: layer, - buffers: buffers, - zoom: this.zoom, - overscaling: this.overscaling, - collisionDebug: this.collisionDebug - }); - - bucketsById[layer.id] = bucket; - - if (data.layers) { // vectortile - sourceLayerId = layer['source-layer']; - bucketsBySourceLayer[sourceLayerId] = bucketsBySourceLayer[sourceLayerId] || {}; - bucketsBySourceLayer[sourceLayerId][layer.id] = bucket; - } - } - - // Index ref layers. - for (i = 0; i < layers.length; i++) { - layer = layers[i]; - if (layer.source === this.source && layer.ref && bucketsById[layer.ref]) { - bucketsById[layer.ref].layers.push(layer.id); - } - } - - // read each layer, and sort its features into buckets - if (data.layers) { // vectortile - for (sourceLayerId in bucketsBySourceLayer) { - layer = data.layers[sourceLayerId]; - if (layer) { - sortLayerIntoBuckets(layer, bucketsBySourceLayer[sourceLayerId]); + throw new Error('Unknown function type "' + type + '"'); + } + + if (zoomAndFeatureDependent) { + var featureFunctions = {}; + var featureFunctionStops = []; + for (var s = 0; s < parameters.stops.length; s++) { + var stop = parameters.stops[s]; + if (featureFunctions[stop[0].zoom] === undefined) { + featureFunctions[stop[0].zoom] = { + zoom: stop[0].zoom, + type: parameters.type, + property: parameters.property, + stops: [] + }; + } + featureFunctions[stop[0].zoom].stops.push([stop[0].value, stop[1]]); } - } - } else { // geojson - sortLayerIntoBuckets(data, bucketsById); - } - function sortLayerIntoBuckets(layer, buckets) { - for (var i = 0; i < layer.length; i++) { - var feature = layer.feature(i); - for (var id in buckets) { - if (buckets[id].filter(feature)) - buckets[id].features.push(feature); + for (var z in featureFunctions) { + featureFunctionStops.push([featureFunctions[z].zoom, createFunction(featureFunctions[z])]); } - } - } - - var buckets = [], - symbolBuckets = this.symbolBuckets = [], - otherBuckets = []; - - var collisionTile = new CollisionTile(this.angle, this.pitch); - - for (var id in bucketsById) { - bucket = bucketsById[id]; - if (bucket.features.length === 0) continue; - - buckets.push(bucket); - - if (bucket.type === 'symbol') - symbolBuckets.push(bucket); - else - otherBuckets.push(bucket); - } - - var icons = {}, - stacks = {}; - - if (symbolBuckets.length > 0) { - - // Get dependencies for symbol buckets - for (i = symbolBuckets.length - 1; i >= 0; i--) { - symbolBuckets[i].updateIcons(icons); - symbolBuckets[i].updateFont(stacks); - } - - for (var fontName in stacks) { - stacks[fontName] = Object.keys(stacks[fontName]).map(Number); - } - icons = Object.keys(icons); - - var deps = 0; - - actor.send('get glyphs', {uid: this.uid, stacks: stacks}, function(err, newStacks) { - stacks = newStacks; - gotDependency(err); - }); + fun = function(zoom, feature) { + return evaluateExponentialFunction({ stops: featureFunctionStops, base: parameters.base }, zoom)(zoom, feature); + }; + fun.isFeatureConstant = false; + fun.isZoomConstant = false; - if (icons.length) { - actor.send('get icons', {icons: icons}, function(err, newIcons) { - icons = newIcons; - gotDependency(err); - }); + } else if (zoomDependent) { + fun = function(zoom) { + return innerFun(parameters, zoom); + }; + fun.isFeatureConstant = true; + fun.isZoomConstant = false; } else { - gotDependency(); + fun = function(zoom, feature) { + return innerFun(parameters, feature[parameters.property]); + }; + fun.isFeatureConstant = false; + fun.isZoomConstant = true; } } - // immediately parse non-symbol buckets (they have no dependencies) - for (i = otherBuckets.length - 1; i >= 0; i--) { - parseBucket(this, otherBuckets[i]); - } - - if (symbolBuckets.length === 0) - return done(); + return fun; +} - function gotDependency(err) { - if (err) return callback(err); - deps++; - if (deps === 2) { - // all symbol bucket dependencies fetched; parse them in proper order - for (var i = symbolBuckets.length - 1; i >= 0; i--) { - parseBucket(tile, symbolBuckets[i]); - } - done(); +function evaluateCategoricalFunction(parameters, input) { + for (var i = 0; i < parameters.stops.length; i++) { + if (input === parameters.stops[i][0]) { + return parameters.stops[i][1]; } } + return parameters.stops[0][1]; +} - function parseBucket(tile, bucket) { - var now = Date.now(); - bucket.addFeatures(collisionTile, stacks, icons); - var time = Date.now() - now; - - if (bucket.interactive) { - for (var i = 0; i < bucket.features.length; i++) { - var feature = bucket.features[i]; - tile.featureTree.insert(feature.bbox(), bucket.layers, feature); - } - } - - bucket.features = null; - - stats._total += time; - stats[bucket.id] = (stats[bucket.id] || 0) + time; +function evaluateIntervalFunction(parameters, input) { + for (var i = 0; i < parameters.stops.length; i++) { + if (input < parameters.stops[i][0]) break; } + return parameters.stops[Math.max(i - 1, 0)][1]; +} - function done() { - tile.status = 'done'; - - if (tile.redoPlacementAfterDone) { - var result = tile.redoPlacement(tile.angle, tile.pitch).result; - buffers.glyphVertex = result.buffers.glyphVertex; - buffers.iconVertex = result.buffers.iconVertex; - buffers.collisionBoxVertex = result.buffers.collisionBoxVertex; - tile.redoPlacementAfterDone = false; - } +function evaluateExponentialFunction(parameters, input) { + var base = parameters.base !== undefined ? parameters.base : 1; - callback(null, { - elementGroups: getElementGroups(buckets), - buffers: buffers, - bucketStats: stats - }, getTransferables(buffers)); + var i = 0; + while (true) { + if (i >= parameters.stops.length) break; + else if (input <= parameters.stops[i][0]) break; + else i++; } -}; -WorkerTile.prototype.redoPlacement = function(angle, pitch, collisionDebug) { - - if (this.status !== 'done') { - this.redoPlacementAfterDone = true; - this.angle = angle; - return {}; - } + if (i === 0) { + return parameters.stops[i][1]; - var buffers = {}, - collisionTile = new CollisionTile(angle, pitch); + } else if (i === parameters.stops.length) { + return parameters.stops[i - 1][1]; - for (var i = this.symbolBuckets.length - 1; i >= 0; i--) { - this.symbolBuckets[i].placeFeatures(collisionTile, buffers, collisionDebug); + } else { + return interpolate( + input, + base, + parameters.stops[i - 1][0], + parameters.stops[i][0], + parameters.stops[i - 1][1], + parameters.stops[i][1] + ); } +} - return { - result: { - elementGroups: getElementGroups(this.symbolBuckets), - buffers: buffers - }, - transferables: getTransferables(buffers) - }; -}; +function evaluateIdentityFunction(parameters, input) { + return input; +} -function getElementGroups(buckets) { - var elementGroups = {}; - for (var i = 0; i < buckets.length; i++) { - elementGroups[buckets[i].id] = buckets[i].elementGroups; +function interpolate(input, base, inputLower, inputUpper, outputLower, outputUpper) { + if (typeof outputLower === 'function') { + return function() { + var evaluatedLower = outputLower.apply(undefined, arguments); + var evaluatedUpper = outputUpper.apply(undefined, arguments); + return interpolate(input, base, inputLower, inputUpper, evaluatedLower, evaluatedUpper); + }; + } else if (outputLower.length) { + return interpolateArray(input, base, inputLower, inputUpper, outputLower, outputUpper); + } else { + return interpolateNumber(input, base, inputLower, inputUpper, outputLower, outputUpper); } - return elementGroups; } -function getTransferables(buffers) { - var transferables = []; +function interpolateNumber(input, base, inputLower, inputUpper, outputLower, outputUpper) { + var difference = inputUpper - inputLower; + var progress = input - inputLower; + + var ratio; + if (base === 1) { + ratio = progress / difference; + } else { + ratio = (Math.pow(base, progress) - 1) / (Math.pow(base, difference) - 1); + } - for (var k in buffers) { - transferables.push(buffers[k].arrayBuffer); + return (outputLower * (1 - ratio)) + (outputUpper * ratio); +} - // The Buffer::push method is generated with "new Function(...)" and not transferrable. - buffers[k].push = null; +function interpolateArray(input, base, inputLower, inputUpper, outputLower, outputUpper) { + var output = []; + for (var i = 0; i < outputLower.length; i++) { + output[i] = interpolateNumber(input, base, inputLower, inputUpper, outputLower[i], outputUpper[i]); } - return transferables; + return output; } -},{"../data/bucket":16,"../data/feature_tree":20,"../symbol/collision_tile":76}],56:[function(require,module,exports){ -'use strict'; +function isFunctionDefinition(value) { + return typeof value === 'object' && (value.stops || value.type === 'identity'); +} -module.exports = AnimationLoop; -function AnimationLoop() { - this.n = 0; - this.times = []; -} +module.exports.isFunctionDefinition = isFunctionDefinition; -// Are all animations done? -AnimationLoop.prototype.stopped = function() { - this.times = this.times.filter(function(t) { - return t.time >= (new Date()).getTime(); - }); - return !this.times.length; +module.exports.interpolated = function(parameters) { + return createFunction(parameters, 'exponential'); }; -// Add a new animation that will run t milliseconds -// Returns an id that can be used to cancel it layer -AnimationLoop.prototype.set = function(t) { - this.times.push({ id: this.n, time: t + (new Date()).getTime() }); - return this.n++; +module.exports['piecewise-constant'] = function(parameters) { + return createFunction(parameters, 'interval'); }; -// Cancel an animation -AnimationLoop.prototype.cancel = function(n) { - this.times = this.times.filter(function(t) { - return t.id !== n; - }); -}; +},{}],46:[function(require,module,exports){ + +var path = require('path'); + +// readFileSync calls must be written out long-form for brfs. +module.exports = { + debug: { + fragmentSource: "#ifdef GL_ES\r\nprecision mediump float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nuniform lowp vec4 u_color;\r\n\r\nvoid main() {\r\n gl_FragColor = u_color;\r\n}\r\n", + vertexSource: "#ifdef GL_ES\r\nprecision highp float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nattribute vec2 a_pos;\r\n\r\nuniform mat4 u_matrix;\r\n\r\nvoid main() {\r\n gl_Position = u_matrix * vec4(a_pos, step(32767.0, a_pos.x), 1);\r\n}\r\n" + }, + fill: { + fragmentSource: "#ifdef GL_ES\r\nprecision mediump float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\n#pragma mapbox: define lowp vec4 color\r\n#pragma mapbox: define lowp float opacity\r\n\r\nvoid main() {\r\n #pragma mapbox: initialize lowp vec4 color\r\n #pragma mapbox: initialize lowp float opacity\r\n\r\n gl_FragColor = color * opacity;\r\n\r\n#ifdef OVERDRAW_INSPECTOR\r\n gl_FragColor = vec4(1.0);\r\n#endif\r\n}\r\n", + vertexSource: "#ifdef GL_ES\r\nprecision highp float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nattribute vec2 a_pos;\r\n\r\nuniform mat4 u_matrix;\r\n\r\n#pragma mapbox: define lowp vec4 color\r\n#pragma mapbox: define lowp float opacity\r\n\r\nvoid main() {\r\n #pragma mapbox: initialize lowp vec4 color\r\n #pragma mapbox: initialize lowp float opacity\r\n\r\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\r\n}\r\n" + }, + circle: { + fragmentSource: "#ifdef GL_ES\r\nprecision mediump float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\n#pragma mapbox: define lowp vec4 color\r\n#pragma mapbox: define lowp float blur\r\n#pragma mapbox: define lowp float opacity\r\n\r\nvarying vec2 v_extrude;\r\nvarying lowp float v_antialiasblur;\r\n\r\nvoid main() {\r\n #pragma mapbox: initialize lowp vec4 color\r\n #pragma mapbox: initialize lowp float blur\r\n #pragma mapbox: initialize lowp float opacity\r\n\r\n float t = smoothstep(1.0 - max(blur, v_antialiasblur), 1.0, length(v_extrude));\r\n gl_FragColor = color * (1.0 - t) * opacity;\r\n\r\n#ifdef OVERDRAW_INSPECTOR\r\n gl_FragColor = vec4(1.0);\r\n#endif\r\n}\r\n", + vertexSource: "#ifdef GL_ES\r\nprecision highp float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nuniform mat4 u_matrix;\r\nuniform bool u_scale_with_map;\r\nuniform vec2 u_extrude_scale;\r\nuniform float u_devicepixelratio;\r\n\r\nattribute vec2 a_pos;\r\n\r\n#pragma mapbox: define lowp vec4 color\r\n#pragma mapbox: define mediump float radius\r\n#pragma mapbox: define lowp float blur\r\n#pragma mapbox: define lowp float opacity\r\n\r\nvarying vec2 v_extrude;\r\nvarying lowp float v_antialiasblur;\r\n\r\nvoid main(void) {\r\n #pragma mapbox: initialize lowp vec4 color\r\n #pragma mapbox: initialize mediump float radius\r\n #pragma mapbox: initialize lowp float blur\r\n #pragma mapbox: initialize lowp float opacity\r\n\r\n // unencode the extrusion vector that we snuck into the a_pos vector\r\n v_extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0);\r\n\r\n vec2 extrude = v_extrude * radius * u_extrude_scale;\r\n // multiply a_pos by 0.5, since we had it * 2 in order to sneak\r\n // in extrusion data\r\n gl_Position = u_matrix * vec4(floor(a_pos * 0.5), 0, 1);\r\n\r\n if (u_scale_with_map) {\r\n gl_Position.xy += extrude;\r\n } else {\r\n gl_Position.xy += extrude * gl_Position.w;\r\n }\r\n\r\n // This is a minimum blur distance that serves as a faux-antialiasing for\r\n // the circle. since blur is a ratio of the circle's size and the intent is\r\n // to keep the blur at roughly 1px, the two are inversely related.\r\n v_antialiasblur = 1.0 / u_devicepixelratio / radius;\r\n}\r\n" + }, + line: { + fragmentSource: "#ifdef GL_ES\r\nprecision mediump float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nuniform lowp float u_opacity;\r\nuniform float u_blur;\r\n\r\n#pragma mapbox: define lowp vec4 color\r\n\r\nvarying vec2 v_linewidth;\r\nvarying vec2 v_normal;\r\nvarying float v_gamma_scale;\r\n\r\nvoid main() {\r\n #pragma mapbox: initialize lowp vec4 color\r\n\r\n // Calculate the distance of the pixel from the line in pixels.\r\n float dist = length(v_normal) * v_linewidth.s;\r\n\r\n // Calculate the antialiasing fade factor. This is either when fading in\r\n // the line in case of an offset line (v_linewidth.t) or when fading out\r\n // (v_linewidth.s)\r\n float blur = u_blur * v_gamma_scale;\r\n float alpha = clamp(min(dist - (v_linewidth.t - blur), v_linewidth.s - dist) / blur, 0.0, 1.0);\r\n\r\n gl_FragColor = color * (alpha * u_opacity);\r\n\r\n#ifdef OVERDRAW_INSPECTOR\r\n gl_FragColor = vec4(1.0);\r\n#endif\r\n}\r\n", + vertexSource: "#ifdef GL_ES\r\nprecision highp float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\n// floor(127 / 2) == 63.0\r\n// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is\r\n// stored in a byte (-128..127). we scale regular normals up to length 63, but\r\n// there are also \"special\" normals that have a bigger length (of up to 126 in\r\n// this case).\r\n// #define scale 63.0\r\n#define scale 0.015873016\r\n\r\nattribute vec2 a_pos;\r\nattribute vec4 a_data;\r\n\r\nuniform mat4 u_matrix;\r\nuniform mediump float u_ratio;\r\nuniform mediump float u_linewidth;\r\nuniform mediump float u_gapwidth;\r\nuniform mediump float u_antialiasing;\r\nuniform mediump float u_extra;\r\nuniform mat2 u_antialiasingmatrix;\r\nuniform mediump float u_offset;\r\nuniform mediump float u_blur;\r\n\r\nvarying vec2 v_normal;\r\nvarying vec2 v_linewidth;\r\nvarying float v_gamma_scale;\r\n\r\n#pragma mapbox: define lowp vec4 color\r\n\r\nvoid main() {\r\n #pragma mapbox: initialize lowp vec4 color\r\n\r\n vec2 a_extrude = a_data.xy - 128.0;\r\n float a_direction = mod(a_data.z, 4.0) - 1.0;\r\n\r\n // We store the texture normals in the most insignificant bit\r\n // transform y so that 0 => -1 and 1 => 1\r\n // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap\r\n // y is 1 if the normal points up, and -1 if it points down\r\n mediump vec2 normal = mod(a_pos, 2.0);\r\n normal.y = sign(normal.y - 0.5);\r\n v_normal = normal;\r\n\r\n float inset = u_gapwidth + (u_gapwidth > 0.0 ? u_antialiasing : 0.0);\r\n float outset = u_gapwidth + u_linewidth * (u_gapwidth > 0.0 ? 2.0 : 1.0) + u_antialiasing;\r\n\r\n // Scale the extrusion vector down to a normal and then up by the line width\r\n // of this vertex.\r\n mediump vec2 dist = outset * a_extrude * scale;\r\n\r\n // Calculate the offset when drawing a line that is to the side of the actual line.\r\n // We do this by creating a vector that points towards the extrude, but rotate\r\n // it when we're drawing round end points (a_direction = -1 or 1) since their\r\n // extrude vector points in another direction.\r\n mediump float u = 0.5 * a_direction;\r\n mediump float t = 1.0 - abs(u);\r\n mediump vec2 offset = u_offset * a_extrude * scale * normal.y * mat2(t, -u, u, t);\r\n\r\n // Remove the texture normal bit of the position before scaling it with the\r\n // model/view matrix.\r\n gl_Position = u_matrix * vec4(floor(a_pos * 0.5) + (offset + dist) / u_ratio, 0.0, 1.0);\r\n\r\n // position of y on the screen\r\n float y = gl_Position.y / gl_Position.w;\r\n\r\n // how much features are squished in the y direction by the tilt\r\n float squish_scale = length(a_extrude) / length(u_antialiasingmatrix * a_extrude);\r\n\r\n // how much features are squished in all directions by the perspectiveness\r\n float perspective_scale = 1.0 / (1.0 - min(y * u_extra, 0.9));\r\n\r\n v_linewidth = vec2(outset, inset);\r\n v_gamma_scale = perspective_scale * squish_scale;\r\n}\r\n" + }, + linepattern: { + fragmentSource: "#ifdef GL_ES\r\nprecision mediump float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nuniform float u_blur;\r\n\r\nuniform vec2 u_pattern_size_a;\r\nuniform vec2 u_pattern_size_b;\r\nuniform vec2 u_pattern_tl_a;\r\nuniform vec2 u_pattern_br_a;\r\nuniform vec2 u_pattern_tl_b;\r\nuniform vec2 u_pattern_br_b;\r\nuniform float u_fade;\r\nuniform float u_opacity;\r\n\r\nuniform sampler2D u_image;\r\n\r\nvarying vec2 v_normal;\r\nvarying vec2 v_linewidth;\r\nvarying float v_linesofar;\r\nvarying float v_gamma_scale;\r\n\r\nvoid main() {\r\n // Calculate the distance of the pixel from the line in pixels.\r\n float dist = length(v_normal) * v_linewidth.s;\r\n\r\n // Calculate the antialiasing fade factor. This is either when fading in\r\n // the line in case of an offset line (v_linewidth.t) or when fading out\r\n // (v_linewidth.s)\r\n float blur = u_blur * v_gamma_scale;\r\n float alpha = clamp(min(dist - (v_linewidth.t - blur), v_linewidth.s - dist) / blur, 0.0, 1.0);\r\n\r\n float x_a = mod(v_linesofar / u_pattern_size_a.x, 1.0);\r\n float x_b = mod(v_linesofar / u_pattern_size_b.x, 1.0);\r\n float y_a = 0.5 + (v_normal.y * v_linewidth.s / u_pattern_size_a.y);\r\n float y_b = 0.5 + (v_normal.y * v_linewidth.s / u_pattern_size_b.y);\r\n vec2 pos_a = mix(u_pattern_tl_a, u_pattern_br_a, vec2(x_a, y_a));\r\n vec2 pos_b = mix(u_pattern_tl_b, u_pattern_br_b, vec2(x_b, y_b));\r\n\r\n vec4 color = mix(texture2D(u_image, pos_a), texture2D(u_image, pos_b), u_fade);\r\n\r\n alpha *= u_opacity;\r\n\r\n gl_FragColor = color * alpha;\r\n\r\n#ifdef OVERDRAW_INSPECTOR\r\n gl_FragColor = vec4(1.0);\r\n#endif\r\n}\r\n", + vertexSource: "#ifdef GL_ES\r\nprecision highp float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\n// floor(127 / 2) == 63.0\r\n// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is\r\n// stored in a byte (-128..127). we scale regular normals up to length 63, but\r\n// there are also \"special\" normals that have a bigger length (of up to 126 in\r\n// this case).\r\n// #define scale 63.0\r\n#define scale 0.015873016\r\n\r\n// We scale the distance before adding it to the buffers so that we can store\r\n// long distances for long segments. Use this value to unscale the distance.\r\n#define LINE_DISTANCE_SCALE 2.0\r\n\r\nattribute vec2 a_pos;\r\nattribute vec4 a_data;\r\n\r\nuniform mat4 u_matrix;\r\nuniform mediump float u_ratio;\r\nuniform mediump float u_linewidth;\r\nuniform mediump float u_gapwidth;\r\nuniform mediump float u_antialiasing;\r\nuniform mediump float u_extra;\r\nuniform mat2 u_antialiasingmatrix;\r\nuniform mediump float u_offset;\r\n\r\nvarying vec2 v_normal;\r\nvarying vec2 v_linewidth;\r\nvarying float v_linesofar;\r\nvarying float v_gamma_scale;\r\n\r\nvoid main() {\r\n vec2 a_extrude = a_data.xy - 128.0;\r\n float a_direction = mod(a_data.z, 4.0) - 1.0;\r\n float a_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * LINE_DISTANCE_SCALE;\r\n\r\n // We store the texture normals in the most insignificant bit\r\n // transform y so that 0 => -1 and 1 => 1\r\n // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap\r\n // y is 1 if the normal points up, and -1 if it points down\r\n mediump vec2 normal = mod(a_pos, 2.0);\r\n normal.y = sign(normal.y - 0.5);\r\n v_normal = normal;\r\n\r\n float inset = u_gapwidth + (u_gapwidth > 0.0 ? u_antialiasing : 0.0);\r\n float outset = u_gapwidth + u_linewidth * (u_gapwidth > 0.0 ? 2.0 : 1.0) + u_antialiasing;\r\n\r\n // Scale the extrusion vector down to a normal and then up by the line width\r\n // of this vertex.\r\n mediump vec2 dist = outset * a_extrude * scale;\r\n\r\n // Calculate the offset when drawing a line that is to the side of the actual line.\r\n // We do this by creating a vector that points towards the extrude, but rotate\r\n // it when we're drawing round end points (a_direction = -1 or 1) since their\r\n // extrude vector points in another direction.\r\n mediump float u = 0.5 * a_direction;\r\n mediump float t = 1.0 - abs(u);\r\n mediump vec2 offset = u_offset * a_extrude * scale * normal.y * mat2(t, -u, u, t);\r\n\r\n // Remove the texture normal bit of the position before scaling it with the\r\n // model/view matrix.\r\n gl_Position = u_matrix * vec4(floor(a_pos * 0.5) + (offset + dist) / u_ratio, 0.0, 1.0);\r\n v_linesofar = a_linesofar;\r\n\r\n // position of y on the screen\r\n float y = gl_Position.y / gl_Position.w;\r\n\r\n // how much features are squished in the y direction by the tilt\r\n float squish_scale = length(a_extrude) / length(u_antialiasingmatrix * a_extrude);\r\n\r\n // how much features are squished in all directions by the perspectiveness\r\n float perspective_scale = 1.0 / (1.0 - min(y * u_extra, 0.9));\r\n\r\n v_linewidth = vec2(outset, inset);\r\n v_gamma_scale = perspective_scale * squish_scale;\r\n}\r\n" + }, + linesdfpattern: { + fragmentSource: "#ifdef GL_ES\r\nprecision mediump float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nuniform lowp float u_opacity;\r\n\r\nuniform float u_blur;\r\nuniform sampler2D u_image;\r\nuniform float u_sdfgamma;\r\nuniform float u_mix;\r\n\r\nvarying vec2 v_normal;\r\nvarying vec2 v_linewidth;\r\nvarying vec2 v_tex_a;\r\nvarying vec2 v_tex_b;\r\nvarying float v_gamma_scale;\r\n\r\n#pragma mapbox: define lowp vec4 color\r\n\r\nvoid main() {\r\n #pragma mapbox: initialize lowp vec4 color\r\n\r\n // Calculate the distance of the pixel from the line in pixels.\r\n float dist = length(v_normal) * v_linewidth.s;\r\n\r\n // Calculate the antialiasing fade factor. This is either when fading in\r\n // the line in case of an offset line (v_linewidth.t) or when fading out\r\n // (v_linewidth.s)\r\n float blur = u_blur * v_gamma_scale;\r\n float alpha = clamp(min(dist - (v_linewidth.t - blur), v_linewidth.s - dist) / blur, 0.0, 1.0);\r\n\r\n float sdfdist_a = texture2D(u_image, v_tex_a).a;\r\n float sdfdist_b = texture2D(u_image, v_tex_b).a;\r\n float sdfdist = mix(sdfdist_a, sdfdist_b, u_mix);\r\n alpha *= smoothstep(0.5 - u_sdfgamma, 0.5 + u_sdfgamma, sdfdist);\r\n\r\n gl_FragColor = color * (alpha * u_opacity);\r\n\r\n#ifdef OVERDRAW_INSPECTOR\r\n gl_FragColor = vec4(1.0);\r\n#endif\r\n}\r\n", + vertexSource: "#ifdef GL_ES\r\nprecision highp float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\n// floor(127 / 2) == 63.0\r\n// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is\r\n// stored in a byte (-128..127). we scale regular normals up to length 63, but\r\n// there are also \"special\" normals that have a bigger length (of up to 126 in\r\n// this case).\r\n// #define scale 63.0\r\n#define scale 0.015873016\r\n\r\n// We scale the distance before adding it to the buffers so that we can store\r\n// long distances for long segments. Use this value to unscale the distance.\r\n#define LINE_DISTANCE_SCALE 2.0\r\n\r\nattribute vec2 a_pos;\r\nattribute vec4 a_data;\r\n\r\nuniform mat4 u_matrix;\r\nuniform mediump float u_ratio;\r\nuniform mediump float u_linewidth;\r\nuniform mediump float u_gapwidth;\r\nuniform mediump float u_antialiasing;\r\nuniform vec2 u_patternscale_a;\r\nuniform float u_tex_y_a;\r\nuniform vec2 u_patternscale_b;\r\nuniform float u_tex_y_b;\r\nuniform float u_extra;\r\nuniform mat2 u_antialiasingmatrix;\r\nuniform mediump float u_offset;\r\n\r\nvarying vec2 v_normal;\r\nvarying vec2 v_linewidth;\r\nvarying vec2 v_tex_a;\r\nvarying vec2 v_tex_b;\r\nvarying float v_gamma_scale;\r\n\r\n#pragma mapbox: define lowp vec4 color\r\n\r\nvoid main() {\r\n #pragma mapbox: initialize lowp vec4 color\r\n\r\n vec2 a_extrude = a_data.xy - 128.0;\r\n float a_direction = mod(a_data.z, 4.0) - 1.0;\r\n float a_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * LINE_DISTANCE_SCALE;\r\n\r\n // We store the texture normals in the most insignificant bit\r\n // transform y so that 0 => -1 and 1 => 1\r\n // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap\r\n // y is 1 if the normal points up, and -1 if it points down\r\n mediump vec2 normal = mod(a_pos, 2.0);\r\n normal.y = sign(normal.y - 0.5);\r\n v_normal = normal;\r\n\r\n float inset = u_gapwidth + (u_gapwidth > 0.0 ? u_antialiasing : 0.0);\r\n float outset = u_gapwidth + u_linewidth * (u_gapwidth > 0.0 ? 2.0 : 1.0) + u_antialiasing;\r\n\r\n // Scale the extrusion vector down to a normal and then up by the line width\r\n // of this vertex.\r\n mediump vec2 dist = outset * a_extrude * scale;\r\n\r\n // Calculate the offset when drawing a line that is to the side of the actual line.\r\n // We do this by creating a vector that points towards the extrude, but rotate\r\n // it when we're drawing round end points (a_direction = -1 or 1) since their\r\n // extrude vector points in another direction.\r\n mediump float u = 0.5 * a_direction;\r\n mediump float t = 1.0 - abs(u);\r\n mediump vec2 offset = u_offset * a_extrude * scale * normal.y * mat2(t, -u, u, t);\r\n\r\n // Remove the texture normal bit of the position before scaling it with the\r\n // model/view matrix.\r\n gl_Position = u_matrix * vec4(floor(a_pos * 0.5) + (offset + dist) / u_ratio, 0.0, 1.0);\r\n\r\n v_tex_a = vec2(a_linesofar * u_patternscale_a.x, normal.y * u_patternscale_a.y + u_tex_y_a);\r\n v_tex_b = vec2(a_linesofar * u_patternscale_b.x, normal.y * u_patternscale_b.y + u_tex_y_b);\r\n\r\n // position of y on the screen\r\n float y = gl_Position.y / gl_Position.w;\r\n\r\n // how much features are squished in the y direction by the tilt\r\n float squish_scale = length(a_extrude) / length(u_antialiasingmatrix * a_extrude);\r\n\r\n // how much features are squished in all directions by the perspectiveness\r\n float perspective_scale = 1.0 / (1.0 - min(y * u_extra, 0.9));\r\n\r\n v_linewidth = vec2(outset, inset);\r\n v_gamma_scale = perspective_scale * squish_scale;\r\n}\r\n" + }, + outline: { + fragmentSource: "#ifdef GL_ES\r\nprecision mediump float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\n#pragma mapbox: define lowp vec4 outline_color\r\n#pragma mapbox: define lowp float opacity\r\n\r\nvarying vec2 v_pos;\r\n\r\nvoid main() {\r\n #pragma mapbox: initialize lowp vec4 outline_color\r\n #pragma mapbox: initialize lowp float opacity\r\n\r\n float dist = length(v_pos - gl_FragCoord.xy);\r\n float alpha = smoothstep(1.0, 0.0, dist);\r\n gl_FragColor = outline_color * (alpha * opacity);\r\n\r\n#ifdef OVERDRAW_INSPECTOR\r\n gl_FragColor = vec4(1.0);\r\n#endif\r\n}\r\n", + vertexSource: "#ifdef GL_ES\r\nprecision highp float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nattribute vec2 a_pos;\r\n\r\nuniform mat4 u_matrix;\r\nuniform vec2 u_world;\r\n\r\nvarying vec2 v_pos;\r\n\r\n#pragma mapbox: define lowp vec4 outline_color\r\n#pragma mapbox: define lowp float opacity\r\n\r\nvoid main() {\r\n #pragma mapbox: initialize lowp vec4 outline_color\r\n #pragma mapbox: initialize lowp float opacity\r\n\r\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\r\n v_pos = (gl_Position.xy / gl_Position.w + 1.0) / 2.0 * u_world;\r\n}\r\n" + }, + outlinepattern: { + fragmentSource: "#ifdef GL_ES\r\nprecision mediump float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nuniform float u_opacity;\r\nuniform vec2 u_pattern_tl_a;\r\nuniform vec2 u_pattern_br_a;\r\nuniform vec2 u_pattern_tl_b;\r\nuniform vec2 u_pattern_br_b;\r\nuniform float u_mix;\r\n\r\nuniform sampler2D u_image;\r\n\r\nvarying vec2 v_pos_a;\r\nvarying vec2 v_pos_b;\r\nvarying vec2 v_pos;\r\n\r\nvoid main() {\r\n vec2 imagecoord = mod(v_pos_a, 1.0);\r\n vec2 pos = mix(u_pattern_tl_a, u_pattern_br_a, imagecoord);\r\n vec4 color1 = texture2D(u_image, pos);\r\n\r\n vec2 imagecoord_b = mod(v_pos_b, 1.0);\r\n vec2 pos2 = mix(u_pattern_tl_b, u_pattern_br_b, imagecoord_b);\r\n vec4 color2 = texture2D(u_image, pos2);\r\n\r\n // find distance to outline for alpha interpolation\r\n\r\n float dist = length(v_pos - gl_FragCoord.xy);\r\n float alpha = smoothstep(1.0, 0.0, dist);\r\n \r\n\r\n gl_FragColor = mix(color1, color2, u_mix) * alpha * u_opacity;\r\n\r\n#ifdef OVERDRAW_INSPECTOR\r\n gl_FragColor = vec4(1.0);\r\n#endif\r\n}\r\n", + vertexSource: "#ifdef GL_ES\r\nprecision highp float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nuniform vec2 u_pattern_size_a;\r\nuniform vec2 u_pattern_size_b;\r\nuniform vec2 u_pixel_coord_upper;\r\nuniform vec2 u_pixel_coord_lower;\r\nuniform float u_scale_a;\r\nuniform float u_scale_b;\r\nuniform float u_tile_units_to_pixels;\r\n\r\nattribute vec2 a_pos;\r\n\r\nuniform mat4 u_matrix;\r\nuniform vec2 u_world;\r\n\r\nvarying vec2 v_pos_a;\r\nvarying vec2 v_pos_b;\r\nvarying vec2 v_pos;\r\n\r\nvoid main() {\r\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\r\n vec2 scaled_size_a = u_scale_a * u_pattern_size_a;\r\n vec2 scaled_size_b = u_scale_b * u_pattern_size_b;\r\n\r\n // the correct offset needs to be calculated.\r\n //\r\n // The offset depends on how many pixels are between the world origin and\r\n // the edge of the tile:\r\n // vec2 offset = mod(pixel_coord, size)\r\n //\r\n // At high zoom levels there are a ton of pixels between the world origin\r\n // and the edge of the tile. The glsl spec only guarantees 16 bits of\r\n // precision for highp floats. We need more than that.\r\n //\r\n // The pixel_coord is passed in as two 16 bit values:\r\n // pixel_coord_upper = floor(pixel_coord / 2^16)\r\n // pixel_coord_lower = mod(pixel_coord, 2^16)\r\n //\r\n // The offset is calculated in a series of steps that should preserve this precision:\r\n vec2 offset_a = mod(mod(mod(u_pixel_coord_upper, scaled_size_a) * 256.0, scaled_size_a) * 256.0 + u_pixel_coord_lower, scaled_size_a);\r\n vec2 offset_b = mod(mod(mod(u_pixel_coord_upper, scaled_size_b) * 256.0, scaled_size_b) * 256.0 + u_pixel_coord_lower, scaled_size_b);\r\n\r\n v_pos_a = (u_tile_units_to_pixels * a_pos + offset_a) / scaled_size_a;\r\n v_pos_b = (u_tile_units_to_pixels * a_pos + offset_b) / scaled_size_b;\r\n\r\n v_pos = (gl_Position.xy / gl_Position.w + 1.0) / 2.0 * u_world;\r\n}\r\n" + }, + pattern: { + fragmentSource: "#ifdef GL_ES\r\nprecision mediump float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nuniform float u_opacity;\r\nuniform vec2 u_pattern_tl_a;\r\nuniform vec2 u_pattern_br_a;\r\nuniform vec2 u_pattern_tl_b;\r\nuniform vec2 u_pattern_br_b;\r\nuniform float u_mix;\r\n\r\nuniform sampler2D u_image;\r\n\r\nvarying vec2 v_pos_a;\r\nvarying vec2 v_pos_b;\r\n\r\nvoid main() {\r\n\r\n vec2 imagecoord = mod(v_pos_a, 1.0);\r\n vec2 pos = mix(u_pattern_tl_a, u_pattern_br_a, imagecoord);\r\n vec4 color1 = texture2D(u_image, pos);\r\n\r\n vec2 imagecoord_b = mod(v_pos_b, 1.0);\r\n vec2 pos2 = mix(u_pattern_tl_b, u_pattern_br_b, imagecoord_b);\r\n vec4 color2 = texture2D(u_image, pos2);\r\n\r\n gl_FragColor = mix(color1, color2, u_mix) * u_opacity;\r\n\r\n#ifdef OVERDRAW_INSPECTOR\r\n gl_FragColor = vec4(1.0);\r\n#endif\r\n}\r\n", + vertexSource: "#ifdef GL_ES\r\nprecision highp float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nuniform mat4 u_matrix;\r\nuniform vec2 u_pattern_size_a;\r\nuniform vec2 u_pattern_size_b;\r\nuniform vec2 u_pixel_coord_upper;\r\nuniform vec2 u_pixel_coord_lower;\r\nuniform float u_scale_a;\r\nuniform float u_scale_b;\r\nuniform float u_tile_units_to_pixels;\r\n\r\nattribute vec2 a_pos;\r\n\r\nvarying vec2 v_pos_a;\r\nvarying vec2 v_pos_b;\r\n\r\nvoid main() {\r\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\r\n vec2 scaled_size_a = u_scale_a * u_pattern_size_a;\r\n vec2 scaled_size_b = u_scale_b * u_pattern_size_b;\r\n\r\n // the correct offset needs to be calculated.\r\n //\r\n // The offset depends on how many pixels are between the world origin and\r\n // the edge of the tile:\r\n // vec2 offset = mod(pixel_coord, size)\r\n //\r\n // At high zoom levels there are a ton of pixels between the world origin\r\n // and the edge of the tile. The glsl spec only guarantees 16 bits of\r\n // precision for highp floats. We need more than that.\r\n //\r\n // The pixel_coord is passed in as two 16 bit values:\r\n // pixel_coord_upper = floor(pixel_coord / 2^16)\r\n // pixel_coord_lower = mod(pixel_coord, 2^16)\r\n //\r\n // The offset is calculated in a series of steps that should preserve this precision:\r\n vec2 offset_a = mod(mod(mod(u_pixel_coord_upper, scaled_size_a) * 256.0, scaled_size_a) * 256.0 + u_pixel_coord_lower, scaled_size_a);\r\n vec2 offset_b = mod(mod(mod(u_pixel_coord_upper, scaled_size_b) * 256.0, scaled_size_b) * 256.0 + u_pixel_coord_lower, scaled_size_b);\r\n\r\n v_pos_a = (u_tile_units_to_pixels * a_pos + offset_a) / scaled_size_a;\r\n v_pos_b = (u_tile_units_to_pixels * a_pos + offset_b) / scaled_size_b;\r\n}\r\n" + }, + raster: { + fragmentSource: "#ifdef GL_ES\r\nprecision mediump float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nuniform float u_opacity0;\r\nuniform float u_opacity1;\r\nuniform sampler2D u_image0;\r\nuniform sampler2D u_image1;\r\nvarying vec2 v_pos0;\r\nvarying vec2 v_pos1;\r\n\r\nuniform float u_brightness_low;\r\nuniform float u_brightness_high;\r\n\r\nuniform float u_saturation_factor;\r\nuniform float u_contrast_factor;\r\nuniform vec3 u_spin_weights;\r\n\r\nvoid main() {\r\n\r\n // read and cross-fade colors from the main and parent tiles\r\n vec4 color0 = texture2D(u_image0, v_pos0);\r\n vec4 color1 = texture2D(u_image1, v_pos1);\r\n vec4 color = color0 * u_opacity0 + color1 * u_opacity1;\r\n vec3 rgb = color.rgb;\r\n\r\n // spin\r\n rgb = vec3(\r\n dot(rgb, u_spin_weights.xyz),\r\n dot(rgb, u_spin_weights.zxy),\r\n dot(rgb, u_spin_weights.yzx));\r\n\r\n // saturation\r\n float average = (color.r + color.g + color.b) / 3.0;\r\n rgb += (average - rgb) * u_saturation_factor;\r\n\r\n // contrast\r\n rgb = (rgb - 0.5) * u_contrast_factor + 0.5;\r\n\r\n // brightness\r\n vec3 u_high_vec = vec3(u_brightness_low, u_brightness_low, u_brightness_low);\r\n vec3 u_low_vec = vec3(u_brightness_high, u_brightness_high, u_brightness_high);\r\n\r\n gl_FragColor = vec4(mix(u_high_vec, u_low_vec, rgb), color.a);\r\n\r\n#ifdef OVERDRAW_INSPECTOR\r\n gl_FragColor = vec4(1.0);\r\n#endif\r\n}\r\n", + vertexSource: "#ifdef GL_ES\r\nprecision highp float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nuniform mat4 u_matrix;\r\nuniform vec2 u_tl_parent;\r\nuniform float u_scale_parent;\r\nuniform float u_buffer_scale;\r\n\r\nattribute vec2 a_pos;\r\nattribute vec2 a_texture_pos;\r\n\r\nvarying vec2 v_pos0;\r\nvarying vec2 v_pos1;\r\n\r\nvoid main() {\r\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\r\n v_pos0 = (((a_texture_pos / 32767.0) - 0.5) / u_buffer_scale ) + 0.5;\r\n v_pos1 = (v_pos0 * u_scale_parent) + u_tl_parent;\r\n}\r\n" + }, + icon: { + fragmentSource: "#ifdef GL_ES\r\nprecision mediump float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nuniform sampler2D u_texture;\r\nuniform sampler2D u_fadetexture;\r\nuniform lowp float u_opacity;\r\n\r\nvarying vec2 v_tex;\r\nvarying vec2 v_fade_tex;\r\n\r\nvoid main() {\r\n lowp float alpha = texture2D(u_fadetexture, v_fade_tex).a * u_opacity;\r\n gl_FragColor = texture2D(u_texture, v_tex) * alpha;\r\n\r\n#ifdef OVERDRAW_INSPECTOR\r\n gl_FragColor = vec4(1.0);\r\n#endif\r\n}\r\n", + vertexSource: "#ifdef GL_ES\r\nprecision highp float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nattribute vec2 a_pos;\r\nattribute vec2 a_offset;\r\nattribute vec2 a_texture_pos;\r\nattribute vec4 a_data;\r\n\r\n\r\n// matrix is for the vertex position.\r\nuniform mat4 u_matrix;\r\n\r\nuniform mediump float u_zoom;\r\nuniform bool u_rotate_with_map;\r\nuniform vec2 u_extrude_scale;\r\n\r\nuniform vec2 u_texsize;\r\n\r\nvarying vec2 v_tex;\r\nvarying vec2 v_fade_tex;\r\n\r\nvoid main() {\r\n vec2 a_tex = a_texture_pos.xy;\r\n mediump float a_labelminzoom = a_data[0];\r\n mediump vec2 a_zoom = a_data.pq;\r\n mediump float a_minzoom = a_zoom[0];\r\n mediump float a_maxzoom = a_zoom[1];\r\n\r\n // u_zoom is the current zoom level adjusted for the change in font size\r\n mediump float z = 2.0 - step(a_minzoom, u_zoom) - (1.0 - step(a_maxzoom, u_zoom));\r\n\r\n vec2 extrude = u_extrude_scale * (a_offset / 64.0);\r\n if (u_rotate_with_map) {\r\n gl_Position = u_matrix * vec4(a_pos + extrude, 0, 1);\r\n gl_Position.z += z * gl_Position.w;\r\n } else {\r\n gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0);\r\n }\r\n\r\n v_tex = a_tex / u_texsize;\r\n v_fade_tex = vec2(a_labelminzoom / 255.0, 0.0);\r\n}\r\n" + }, + sdf: { + fragmentSource: "#ifdef GL_ES\r\nprecision mediump float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nuniform sampler2D u_texture;\r\nuniform sampler2D u_fadetexture;\r\nuniform lowp vec4 u_color;\r\nuniform lowp float u_opacity;\r\nuniform lowp float u_buffer;\r\nuniform lowp float u_gamma;\r\n\r\nvarying vec2 v_tex;\r\nvarying vec2 v_fade_tex;\r\nvarying float v_gamma_scale;\r\n\r\nvoid main() {\r\n lowp float dist = texture2D(u_texture, v_tex).a;\r\n lowp float fade_alpha = texture2D(u_fadetexture, v_fade_tex).a;\r\n lowp float gamma = u_gamma * v_gamma_scale;\r\n lowp float alpha = smoothstep(u_buffer - gamma, u_buffer + gamma, dist) * fade_alpha;\r\n\r\n gl_FragColor = u_color * (alpha * u_opacity);\r\n\r\n#ifdef OVERDRAW_INSPECTOR\r\n gl_FragColor = vec4(1.0);\r\n#endif\r\n}\r\n", + vertexSource: "#ifdef GL_ES\r\nprecision highp float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nconst float PI = 3.141592653589793;\r\n\r\nattribute vec2 a_pos;\r\nattribute vec2 a_offset;\r\nattribute vec2 a_texture_pos;\r\nattribute vec4 a_data;\r\n\r\n\r\n// matrix is for the vertex position.\r\nuniform mat4 u_matrix;\r\n\r\nuniform mediump float u_zoom;\r\nuniform bool u_rotate_with_map;\r\nuniform bool u_pitch_with_map;\r\nuniform mediump float u_pitch;\r\nuniform mediump float u_bearing;\r\nuniform mediump float u_aspect_ratio;\r\nuniform vec2 u_extrude_scale;\r\n\r\nuniform vec2 u_texsize;\r\n\r\nvarying vec2 v_tex;\r\nvarying vec2 v_fade_tex;\r\nvarying float v_gamma_scale;\r\n\r\nvoid main() {\r\n vec2 a_tex = a_texture_pos.xy;\r\n mediump float a_labelminzoom = a_data[0];\r\n mediump vec2 a_zoom = a_data.pq;\r\n mediump float a_minzoom = a_zoom[0];\r\n mediump float a_maxzoom = a_zoom[1];\r\n\r\n // u_zoom is the current zoom level adjusted for the change in font size\r\n mediump float z = 2.0 - step(a_minzoom, u_zoom) - (1.0 - step(a_maxzoom, u_zoom));\r\n\r\n // pitch-alignment: map\r\n // rotation-alignment: map | viewport\r\n if (u_pitch_with_map) {\r\n lowp float angle = u_rotate_with_map ? (a_data[1] / 256.0 * 2.0 * PI) : u_bearing;\r\n lowp float asin = sin(angle);\r\n lowp float acos = cos(angle);\r\n mat2 RotationMatrix = mat2(acos, asin, -1.0 * asin, acos);\r\n vec2 offset = RotationMatrix * a_offset;\r\n vec2 extrude = u_extrude_scale * (offset / 64.0);\r\n gl_Position = u_matrix * vec4(a_pos + extrude, 0, 1);\r\n gl_Position.z += z * gl_Position.w;\r\n // pitch-alignment: viewport\r\n // rotation-alignment: map\r\n } else if (u_rotate_with_map) {\r\n // foreshortening factor to apply on pitched maps\r\n // as a label goes from horizontal <=> vertical in angle\r\n // it goes from 0% foreshortening to up to around 70% foreshortening\r\n lowp float pitchfactor = 1.0 - cos(u_pitch * sin(u_pitch * 0.75));\r\n\r\n lowp float lineangle = a_data[1] / 256.0 * 2.0 * PI;\r\n\r\n // use the lineangle to position points a,b along the line\r\n // project the points and calculate the label angle in projected space\r\n // this calculation allows labels to be rendered unskewed on pitched maps\r\n vec4 a = u_matrix * vec4(a_pos, 0, 1);\r\n vec4 b = u_matrix * vec4(a_pos + vec2(cos(lineangle),sin(lineangle)), 0, 1);\r\n lowp float angle = atan((b[1]/b[3] - a[1]/a[3])/u_aspect_ratio, b[0]/b[3] - a[0]/a[3]);\r\n lowp float asin = sin(angle);\r\n lowp float acos = cos(angle);\r\n mat2 RotationMatrix = mat2(acos, -1.0 * asin, asin, acos);\r\n\r\n vec2 offset = RotationMatrix * (vec2((1.0-pitchfactor)+(pitchfactor*cos(angle*2.0)), 1.0) * a_offset);\r\n vec2 extrude = u_extrude_scale * (offset / 64.0);\r\n gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0);\r\n gl_Position.z += z * gl_Position.w;\r\n // pitch-alignment: viewport\r\n // rotation-alignment: viewport\r\n } else {\r\n vec2 extrude = u_extrude_scale * (a_offset / 64.0);\r\n gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0);\r\n }\r\n\r\n v_gamma_scale = (gl_Position.w - 0.5);\r\n\r\n v_tex = a_tex / u_texsize;\r\n v_fade_tex = vec2(a_labelminzoom / 255.0, 0.0);\r\n}\r\n" + }, + collisionbox: { + fragmentSource: "#ifdef GL_ES\r\nprecision mediump float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nuniform float u_zoom;\r\nuniform float u_maxzoom;\r\n\r\nvarying float v_max_zoom;\r\nvarying float v_placement_zoom;\r\n\r\nvoid main() {\r\n\r\n float alpha = 0.5;\r\n\r\n gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0) * alpha;\r\n\r\n if (v_placement_zoom > u_zoom) {\r\n gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * alpha;\r\n }\r\n\r\n if (u_zoom >= v_max_zoom) {\r\n gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0) * alpha * 0.25;\r\n }\r\n\r\n if (v_placement_zoom >= u_maxzoom) {\r\n gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0) * alpha * 0.2;\r\n }\r\n}\r\n", + vertexSource: "#ifdef GL_ES\r\nprecision highp float;\r\n#else\r\n#define lowp\r\n#define mediump\r\n#define highp\r\n#endif\r\n\r\nattribute vec2 a_pos;\r\nattribute vec2 a_extrude;\r\nattribute vec2 a_data;\r\n\r\nuniform mat4 u_matrix;\r\nuniform float u_scale;\r\n\r\nvarying float v_max_zoom;\r\nvarying float v_placement_zoom;\r\n\r\nvoid main() {\r\n gl_Position = u_matrix * vec4(a_pos + a_extrude / u_scale, 0.0, 1.0);\r\n\r\n v_max_zoom = a_data.x;\r\n v_placement_zoom = a_data.y;\r\n}\r\n" + } +}; + +module.exports.util = "float evaluate_zoom_function_1(const vec4 values, const float t) {\r\n if (t < 1.0) {\r\n return mix(values[0], values[1], t);\r\n } else if (t < 2.0) {\r\n return mix(values[1], values[2], t - 1.0);\r\n } else {\r\n return mix(values[2], values[3], t - 2.0);\r\n }\r\n}\r\nvec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {\r\n if (t < 1.0) {\r\n return mix(value0, value1, t);\r\n } else if (t < 2.0) {\r\n return mix(value1, value2, t - 1.0);\r\n } else {\r\n return mix(value2, value3, t - 2.0);\r\n }\r\n}\r\n"; -},{}],57:[function(require,module,exports){ -'use strict'; +},{"path":194}],47:[function(require,module,exports){ +'use strict'; + +var format = require('util').format; + +function ValidationError(key, value /*, message, ...*/) { + this.message = ( + (key ? key + ': ' : '') + + format.apply(format, Array.prototype.slice.call(arguments, 2)) + ); + + if (value !== null && value !== undefined && value.__line__) { + this.line = value.__line__; + } +} + +module.exports = ValidationError; -var Evented = require('../util/evented'); -var ajax = require('../util/ajax'); -var browser = require('../util/browser'); -var normalizeURL = require('../util/mapbox').normalizeSpriteURL; +},{"util":211}],48:[function(require,module,exports){ +'use strict'; + +module.exports = function (output) { + for (var i = 1; i < arguments.length; i++) { + var input = arguments[i]; + for (var k in input) { + output[k] = input[k]; + } + } + return output; +}; -module.exports = ImageSprite; +},{}],49:[function(require,module,exports){ +'use strict'; + +module.exports = function getType(val) { + if (val instanceof Number) { + return 'number'; + } else if (val instanceof String) { + return 'string'; + } else if (val instanceof Boolean) { + return 'boolean'; + } else if (Array.isArray(val)) { + return 'array'; + } else if (val === null) { + return 'null'; + } else { + return typeof val; + } +}; -function ImageSprite(base) { - this.base = base; - this.retina = browser.devicePixelRatio > 1; +},{}],50:[function(require,module,exports){ +'use strict'; + +// Turn jsonlint-lines-primitives objects into primitive objects +module.exports = function unbundle(value) { + if (value instanceof Number || value instanceof String || value instanceof Boolean) { + return value.valueOf(); + } else { + return value; + } +}; - var format = this.retina ? '@2x' : ''; +},{}],51:[function(require,module,exports){ +'use strict'; + +var ValidationError = require('../error/validation_error'); +var getType = require('../util/get_type'); +var extend = require('../util/extend'); + +// Main recursive validation function. Tracks: +// +// - key: string representing location of validation in style tree. Used only +// for more informative error reporting. +// - value: current value from style being evaluated. May be anything from a +// high level object that needs to be descended into deeper or a simple +// scalar value. +// - valueSpec: current spec being evaluated. Tracks value. + +module.exports = function validate(options) { + + var validateFunction = require('./validate_function'); + var validateObject = require('./validate_object'); + var VALIDATORS = { + '*': function() { + return []; + }, + 'array': require('./validate_array'), + 'boolean': require('./validate_boolean'), + 'number': require('./validate_number'), + 'color': require('./validate_color'), + 'constants': require('./validate_constants'), + 'enum': require('./validate_enum'), + 'filter': require('./validate_filter'), + 'function': require('./validate_function'), + 'layer': require('./validate_layer'), + 'object': require('./validate_object'), + 'source': require('./validate_source'), + 'string': require('./validate_string') + }; + + var value = options.value; + var valueSpec = options.valueSpec; + var key = options.key; + var styleSpec = options.styleSpec; + var style = options.style; + + if (getType(value) === 'string' && value[0] === '@') { + if (styleSpec.$version > 7) { + return [new ValidationError(key, value, 'constants have been deprecated as of v8')]; + } + if (!(value in style.constants)) { + return [new ValidationError(key, value, 'constant "%s" not found', value)]; + } + options = extend({}, options, { value: style.constants[value] }); + } + + if (valueSpec.function && getType(value) === 'object') { + return validateFunction(options); + + } else if (valueSpec.type && VALIDATORS[valueSpec.type]) { + return VALIDATORS[valueSpec.type](options); + + } else { + return validateObject(extend({}, options, { + valueSpec: valueSpec.type ? styleSpec[valueSpec.type] : valueSpec + })); + } +}; - ajax.getJSON(normalizeURL(base, format, '.json'), function(err, data) { - if (err) { - this.fire('error', {error: err}); - return; - } +},{"../error/validation_error":47,"../util/extend":48,"../util/get_type":49,"./validate_array":52,"./validate_boolean":53,"./validate_color":54,"./validate_constants":55,"./validate_enum":56,"./validate_filter":57,"./validate_function":58,"./validate_layer":60,"./validate_number":62,"./validate_object":63,"./validate_source":65,"./validate_string":66}],52:[function(require,module,exports){ +'use strict'; + +var getType = require('../util/get_type'); +var validate = require('./validate'); +var ValidationError = require('../error/validation_error'); + +module.exports = function validateArray(options) { + var array = options.value; + var arraySpec = options.valueSpec; + var style = options.style; + var styleSpec = options.styleSpec; + var key = options.key; + var validateArrayElement = options.arrayElementValidator || validate; + + if (getType(array) !== 'array') { + return [new ValidationError(key, array, 'array expected, %s found', getType(array))]; + } + + if (arraySpec.length && array.length !== arraySpec.length) { + return [new ValidationError(key, array, 'array length %d expected, length %d found', arraySpec.length, array.length)]; + } + + if (arraySpec['min-length'] && array.length < arraySpec['min-length']) { + return [new ValidationError(key, array, 'array length at least %d expected, length %d found', arraySpec['min-length'], array.length)]; + } + + var arrayElementSpec = { + "type": arraySpec.value + }; + + if (styleSpec.$version < 7) { + arrayElementSpec.function = arraySpec.function; + } + + if (getType(arraySpec.value) === 'object') { + arrayElementSpec = arraySpec.value; + } + + var errors = []; + for (var i = 0; i < array.length; i++) { + errors = errors.concat(validateArrayElement({ + array: array, + arrayIndex: i, + value: array[i], + valueSpec: arrayElementSpec, + style: style, + styleSpec: styleSpec, + key: key + '[' + i + ']' + })); + } + return errors; +}; - this.data = data; - if (this.img) this.fire('load'); - }.bind(this)); +},{"../error/validation_error":47,"../util/get_type":49,"./validate":51}],53:[function(require,module,exports){ +'use strict'; + +var getType = require('../util/get_type'); +var ValidationError = require('../error/validation_error'); + +module.exports = function validateBoolean(options) { + var value = options.value; + var key = options.key; + var type = getType(value); + + if (type !== 'boolean') { + return [new ValidationError(key, value, 'boolean expected, %s found', type)]; + } + + return []; +}; - ajax.getImage(normalizeURL(base, format, '.png'), function(err, img) { - if (err) { - this.fire('error', {error: err}); - return; - } +},{"../error/validation_error":47,"../util/get_type":49}],54:[function(require,module,exports){ +'use strict'; + +var ValidationError = require('../error/validation_error'); +var getType = require('../util/get_type'); +var parseCSSColor = require('csscolorparser').parseCSSColor; + +module.exports = function validateColor(options) { + var key = options.key; + var value = options.value; + var type = getType(value); + + if (type !== 'string') { + return [new ValidationError(key, value, 'color expected, %s found', type)]; + } + + if (parseCSSColor(value) === null) { + return [new ValidationError(key, value, 'color expected, "%s" found', value)]; + } + + return []; +}; - // premultiply the sprite - var data = img.getData(); - var newdata = img.data = new Uint8Array(data.length); - for (var i = 0; i < data.length; i += 4) { - var alpha = data[i + 3] / 255; - newdata[i + 0] = data[i + 0] * alpha; - newdata[i + 1] = data[i + 1] * alpha; - newdata[i + 2] = data[i + 2] * alpha; - newdata[i + 3] = data[i + 3]; - } - - this.img = img; - if (this.data) this.fire('load'); - }.bind(this)); -} - -ImageSprite.prototype = Object.create(Evented); - -ImageSprite.prototype.toJSON = function() { - return this.base; -}; - -ImageSprite.prototype.loaded = function() { - return !!(this.data && this.img); -}; - -ImageSprite.prototype.resize = function(/*gl*/) { - if (browser.devicePixelRatio > 1 !== this.retina) { - var newSprite = new ImageSprite(this.base); - newSprite.on('load', function() { - this.img = newSprite.img; - this.data = newSprite.data; - this.retina = newSprite.retina; - }.bind(this)); - } -}; +},{"../error/validation_error":47,"../util/get_type":49,"csscolorparser":10}],55:[function(require,module,exports){ +'use strict'; + +var ValidationError = require('../error/validation_error'); +var getType = require('../util/get_type'); + +module.exports = function validateConstants(options) { + var key = options.key; + var constants = options.value; + var styleSpec = options.styleSpec; + + if (styleSpec.$version > 7) { + if (constants) { + return [new ValidationError(key, constants, 'constants have been deprecated as of v8')]; + } else { + return []; + } + } else { + var type = getType(constants); + if (type !== 'object') { + return [new ValidationError(key, constants, 'object expected, %s found', type)]; + } + + var errors = []; + for (var constantName in constants) { + if (constantName[0] !== '@') { + errors.push(new ValidationError(key + '.' + constantName, constants[constantName], 'constants must start with "@"')); + } + } + return errors; + } + +}; -function SpritePosition() {} -SpritePosition.prototype = { x: 0, y: 0, width: 0, height: 0, pixelRatio: 1, sdf: false }; +},{"../error/validation_error":47,"../util/get_type":49}],56:[function(require,module,exports){ +'use strict'; + +var ValidationError = require('../error/validation_error'); +var unbundle = require('../util/unbundle_jsonlint'); + +module.exports = function validateEnum(options) { + var key = options.key; + var value = options.value; + var valueSpec = options.valueSpec; + var errors = []; + + if (valueSpec.values.indexOf(unbundle(value)) === -1) { + errors.push(new ValidationError(key, value, 'expected one of [%s], %s found', valueSpec.values.join(', '), value)); + } + return errors; +}; -ImageSprite.prototype.getSpritePosition = function(name) { - if (!this.loaded()) return new SpritePosition(); +},{"../error/validation_error":47,"../util/unbundle_jsonlint":50}],57:[function(require,module,exports){ +'use strict'; + +var ValidationError = require('../error/validation_error'); +var validateEnum = require('./validate_enum'); +var getType = require('../util/get_type'); +var unbundle = require('../util/unbundle_jsonlint'); + +module.exports = function validateFilter(options) { + var value = options.value; + var key = options.key; + var styleSpec = options.styleSpec; + var type; + + var errors = []; + + if (getType(value) !== 'array') { + return [new ValidationError(key, value, 'array expected, %s found', getType(value))]; + } + + if (value.length < 1) { + return [new ValidationError(key, value, 'filter array must have at least 1 element')]; + } + + errors = errors.concat(validateEnum({ + key: key + '[0]', + value: value[0], + valueSpec: styleSpec.filter_operator, + style: options.style, + styleSpec: options.styleSpec + })); + + switch (unbundle(value[0])) { + case '<': + case '<=': + case '>': + case '>=': + if (value.length >= 2 && value[1] == '$type') { + errors.push(new ValidationError(key, value, '"$type" cannot be use with operator "%s"', value[0])); + } + /* falls through */ + case '==': + case '!=': + if (value.length != 3) { + errors.push(new ValidationError(key, value, 'filter array for operator "%s" must have 3 elements', value[0])); + } + /* falls through */ + case 'in': + case '!in': + if (value.length >= 2) { + type = getType(value[1]); + if (type !== 'string') { + errors.push(new ValidationError(key + '[1]', value[1], 'string expected, %s found', type)); + } else if (value[1][0] === '@') { + errors.push(new ValidationError(key + '[1]', value[1], 'filter key cannot be a constant')); + } + } + for (var i = 2; i < value.length; i++) { + type = getType(value[i]); + if (value[1] == '$type') { + errors = errors.concat(validateEnum({ + key: key + '[' + i + ']', + value: value[i], + valueSpec: styleSpec.geometry_type, + style: options.style, + styleSpec: options.styleSpec + })); + } else if (type === 'string' && value[i][0] === '@') { + errors.push(new ValidationError(key + '[' + i + ']', value[i], 'filter value cannot be a constant')); + } else if (type !== 'string' && type !== 'number' && type !== 'boolean') { + errors.push(new ValidationError(key + '[' + i + ']', value[i], 'string, number, or boolean expected, %s found', type)); + } + } + break; + + case 'any': + case 'all': + case 'none': + for (i = 1; i < value.length; i++) { + errors = errors.concat(validateFilter({ + key: key + '[' + i + ']', + value: value[i], + style: options.style, + styleSpec: options.styleSpec + })); + } + break; + + case 'has': + case '!has': + type = getType(value[1]); + if (value.length !== 2) { + errors.push(new ValidationError(key, value, 'filter array for "%s" operator must have 2 elements', value[0])); + } else if (type !== 'string') { + errors.push(new ValidationError(key + '[1]', value[1], 'string expected, %s found', type)); + } else if (value[1][0] === '@') { + errors.push(new ValidationError(key + '[1]', value[1], 'filter key cannot be a constant')); + } + break; + + } + + return errors; +}; - var pos = this.data && this.data[name]; - if (pos && this.img) return pos; +},{"../error/validation_error":47,"../util/get_type":49,"../util/unbundle_jsonlint":50,"./validate_enum":56}],58:[function(require,module,exports){ +'use strict'; + +var ValidationError = require('../error/validation_error'); +var getType = require('../util/get_type'); +var validate = require('./validate'); +var validateObject = require('./validate_object'); +var validateArray = require('./validate_array'); +var validateNumber = require('./validate_number'); + +module.exports = function validateFunction(options) { + var functionValueSpec = options.valueSpec; + var stopKeyType; + + var isPropertyFunction = options.value.property !== undefined || stopKeyType === 'object'; + var isZoomFunction = options.value.property === undefined || stopKeyType === 'object'; + + var errors = validateObject({ + key: options.key, + value: options.value, + valueSpec: options.styleSpec.function, + style: options.style, + styleSpec: options.styleSpec, + objectElementValidators: { stops: validateFunctionStops } + }); + + if (options.styleSpec.$version >= 8) { + if (isPropertyFunction && !options.valueSpec['property-function']) { + errors.push(new ValidationError(options.key, options.value, 'property functions not supported')); + } else if (isZoomFunction && !options.valueSpec['zoom-function']) { + errors.push(new ValidationError(options.key, options.value, 'zoom functions not supported')); + } + } + + return errors; + + function validateFunctionStops(options) { + var errors = []; + var value = options.value; + + errors = errors.concat(validateArray({ + key: options.key, + value: value, + valueSpec: options.valueSpec, + style: options.style, + styleSpec: options.styleSpec, + arrayElementValidator: validateFunctionStop + })); + + if (getType(value) === 'array' && value.length === 0) { + errors.push(new ValidationError(options.key, value, 'array must have at least one stop')); + } + + return errors; + } + + function validateFunctionStop(options) { + var errors = []; + var value = options.value; + var key = options.key; + + if (getType(value) !== 'array') { + return [new ValidationError(key, value, 'array expected, %s found', getType(value))]; + } + + if (value.length !== 2) { + return [new ValidationError(key, value, 'array length %d expected, length %d found', 2, value.length)]; + } + + var type = getType(value[0]); + if (!stopKeyType) stopKeyType = type; + if (type !== stopKeyType) { + return [new ValidationError(key, value, '%s stop key type must match previous stop key type %s', type, stopKeyType)]; + } + + if (type === 'object') { + if (value[0].zoom === undefined) { + return [new ValidationError(key, value, 'object stop key must have zoom')]; + } + if (value[0].value === undefined) { + return [new ValidationError(key, value, 'object stop key must have value')]; + } + errors = errors.concat(validateObject({ + key: key + '[0]', + value: value[0], + valueSpec: { zoom: {} }, + style: options.style, + styleSpec: options.styleSpec, + objectElementValidators: { zoom: validateNumber, value: validateValue } + })); + } else { + errors = errors.concat((isZoomFunction ? validateNumber : validateValue)({ + key: key + '[0]', + value: value[0], + valueSpec: {}, + style: options.style, + styleSpec: options.styleSpec + })); + } + + errors = errors.concat(validate({ + key: key + '[1]', + value: value[1], + valueSpec: functionValueSpec, + style: options.style, + styleSpec: options.styleSpec + })); + + if (getType(value[0]) === 'number') { + if (functionValueSpec.function === 'piecewise-constant' && value[0] % 1 !== 0) { + errors.push(new ValidationError(key + '[0]', value[0], 'zoom level for piecewise-constant functions must be an integer')); + } + + if (options.arrayIndex !== 0) { + if (value[0] < options.array[options.arrayIndex - 1][0]) { + errors.push(new ValidationError(key + '[0]', value[0], 'array stops must appear in ascending order')); + } + } + } + + return errors; + } + + function validateValue(options) { + var errors = []; + var type = getType(options.value); + if (type !== 'number' && type !== 'string' && type !== 'array') { + errors.push(new ValidationError(options.key, options.value, 'property value must be a number, string or array')); + } + return errors; + } + +}; - return new SpritePosition(); -}; +},{"../error/validation_error":47,"../util/get_type":49,"./validate":51,"./validate_array":52,"./validate_number":62,"./validate_object":63}],59:[function(require,module,exports){ +'use strict'; + +var ValidationError = require('../error/validation_error'); +var validateString = require('./validate_string'); + +module.exports = function(options) { + var value = options.value; + var key = options.key; + + var errors = validateString(options); + if (errors.length) return errors; + + if (value.indexOf('{fontstack}') === -1) { + errors.push(new ValidationError(key, value, '"glyphs" url must include a "{fontstack}" token')); + } + + if (value.indexOf('{range}') === -1) { + errors.push(new ValidationError(key, value, '"glyphs" url must include a "{range}" token')); + } + + return errors; +}; -},{"../util/ajax":101,"../util/browser":102,"../util/evented":107,"../util/mapbox":110}],58:[function(require,module,exports){ -'use strict'; +},{"../error/validation_error":47,"./validate_string":66}],60:[function(require,module,exports){ +'use strict'; + +var ValidationError = require('../error/validation_error'); +var unbundle = require('../util/unbundle_jsonlint'); +var validateObject = require('./validate_object'); +var validateFilter = require('./validate_filter'); +var validatePaintProperty = require('./validate_paint_property'); +var validateLayoutProperty = require('./validate_layout_property'); +var extend = require('../util/extend'); + +module.exports = function validateLayer(options) { + var errors = []; + + var layer = options.value; + var key = options.key; + var style = options.style; + var styleSpec = options.styleSpec; + + if (!layer.type && !layer.ref) { + errors.push(new ValidationError(key, layer, 'either "type" or "ref" is required')); + } + var type = unbundle(layer.type); + var ref = unbundle(layer.ref); + + if (layer.id) { + for (var i = 0; i < options.arrayIndex; i++) { + var otherLayer = style.layers[i]; + if (unbundle(otherLayer.id) === unbundle(layer.id)) { + errors.push(new ValidationError(key, layer.id, 'duplicate layer id "%s", previously used at line %d', layer.id, otherLayer.id.__line__)); + } + } + } + + if ('ref' in layer) { + ['type', 'source', 'source-layer', 'filter', 'layout'].forEach(function (p) { + if (p in layer) { + errors.push(new ValidationError(key, layer[p], '"%s" is prohibited for ref layers', p)); + } + }); + + var parent; + + style.layers.forEach(function(layer) { + if (layer.id == ref) parent = layer; + }); + + if (!parent) { + errors.push(new ValidationError(key, layer.ref, 'ref layer "%s" not found', ref)); + } else if (parent.ref) { + errors.push(new ValidationError(key, layer.ref, 'ref cannot reference another ref layer')); + } else { + type = unbundle(parent.type); + } + } else if (type !== 'background') { + if (!layer.source) { + errors.push(new ValidationError(key, layer, 'missing required property "source"')); + } else { + var source = style.sources && style.sources[layer.source]; + if (!source) { + errors.push(new ValidationError(key, layer.source, 'source "%s" not found', layer.source)); + } else if (source.type == 'vector' && type == 'raster') { + errors.push(new ValidationError(key, layer.source, 'layer "%s" requires a raster source', layer.id)); + } else if (source.type == 'raster' && type != 'raster') { + errors.push(new ValidationError(key, layer.source, 'layer "%s" requires a vector source', layer.id)); + } else if (source.type == 'vector' && !layer['source-layer']) { + errors.push(new ValidationError(key, layer, 'layer "%s" must specify a "source-layer"', layer.id)); + } + } + } + + errors = errors.concat(validateObject({ + key: key, + value: layer, + valueSpec: styleSpec.layer, + style: options.style, + styleSpec: options.styleSpec, + objectElementValidators: { + filter: validateFilter, + layout: function(options) { + return validateObject({ + layer: layer, + key: options.key, + value: options.value, + style: options.style, + styleSpec: options.styleSpec, + objectElementValidators: { + '*': function(options) { + return validateLayoutProperty(extend({layerType: type}, options)); + } + } + }); + }, + paint: function(options) { + return validateObject({ + layer: layer, + key: options.key, + value: options.value, + style: options.style, + styleSpec: options.styleSpec, + objectElementValidators: { + '*': function(options) { + return validatePaintProperty(extend({layerType: type}, options)); + } + } + }); + } + } + })); + + return errors; +}; -var parseCSSColor = require('csscolorparser').parseCSSColor; -var util = require('../util/util'); +},{"../error/validation_error":47,"../util/extend":48,"../util/unbundle_jsonlint":50,"./validate_filter":57,"./validate_layout_property":61,"./validate_object":63,"./validate_paint_property":64}],61:[function(require,module,exports){ +'use strict'; + +var validate = require('./validate'); +var ValidationError = require('../error/validation_error'); + +module.exports = function validateLayoutProperty(options) { + var key = options.key; + var style = options.style; + var styleSpec = options.styleSpec; + var value = options.value; + var propertyKey = options.objectKey; + var layerSpec = styleSpec['layout_' + options.layerType]; + + if (!layerSpec) return []; + + if (options.valueSpec || layerSpec[propertyKey]) { + var errors = []; + + if (options.layerType === 'symbol') { + if (propertyKey === 'icon-image' && style && !style.sprite) { + errors.push(new ValidationError(key, value, 'use of "icon-image" requires a style "sprite" property')); + } else if (propertyKey === 'text-field' && style && !style.glyphs) { + errors.push(new ValidationError(key, value, 'use of "text-field" requires a style "glyphs" property')); + } + } + + return errors.concat(validate({ + key: options.key, + value: value, + valueSpec: options.valueSpec || layerSpec[propertyKey], + style: style, + styleSpec: styleSpec + })); + + } else { + return [new ValidationError(key, value, 'unknown property "%s"', propertyKey)]; + } + +}; -var colorCache = {}; +},{"../error/validation_error":47,"./validate":51}],62:[function(require,module,exports){ +'use strict'; + +var getType = require('../util/get_type'); +var ValidationError = require('../error/validation_error'); + +module.exports = function validateNumber(options) { + var key = options.key; + var value = options.value; + var valueSpec = options.valueSpec; + var type = getType(value); + + if (type !== 'number') { + return [new ValidationError(key, value, 'number expected, %s found', type)]; + } + + if ('minimum' in valueSpec && value < valueSpec.minimum) { + return [new ValidationError(key, value, '%s is less than the minimum value %s', value, valueSpec.minimum)]; + } + + if ('maximum' in valueSpec && value > valueSpec.maximum) { + return [new ValidationError(key, value, '%s is greater than the maximum value %s', value, valueSpec.maximum)]; + } + + return []; +}; -function parseColor(input) { +},{"../error/validation_error":47,"../util/get_type":49}],63:[function(require,module,exports){ +'use strict'; + +var ValidationError = require('../error/validation_error'); +var getType = require('../util/get_type'); +var validate = require('./validate'); + +module.exports = function validateObject(options) { + var key = options.key; + var object = options.value; + var valueSpec = options.valueSpec; + var objectElementValidators = options.objectElementValidators || {}; + var style = options.style; + var styleSpec = options.styleSpec; + var errors = []; + + var type = getType(object); + if (type !== 'object') { + return [new ValidationError(key, object, 'object expected, %s found', type)]; + } + + for (var objectKey in object) { + var valueSpecKey = objectKey.split('.')[0]; // treat 'paint.*' as 'paint' + var objectElementSpec = valueSpec && (valueSpec[valueSpecKey] || valueSpec['*']); + var objectElementValidator = objectElementValidators[valueSpecKey] || objectElementValidators['*']; + + if (objectElementSpec || objectElementValidator) { + errors = errors.concat((objectElementValidator || validate)({ + key: (key ? key + '.' : key) + objectKey, + value: object[objectKey], + valueSpec: objectElementSpec, + style: style, + styleSpec: styleSpec, + object: object, + objectKey: objectKey + })); + + // tolerate root-level extra keys & arbitrary layer properties + // TODO remove this layer-specific logic + } else if (key !== '' && key.split('.').length !== 1) { + errors.push(new ValidationError(key, object[objectKey], 'unknown property "%s"', objectKey)); + } + } + + for (valueSpecKey in valueSpec) { + if (valueSpec[valueSpecKey].required && valueSpec[valueSpecKey]['default'] === undefined && object[valueSpecKey] === undefined) { + errors.push(new ValidationError(key, object, 'missing required property "%s"', valueSpecKey)); + } + } + + return errors; +}; - if (colorCache[input]) { - return colorCache[input]; +},{"../error/validation_error":47,"../util/get_type":49,"./validate":51}],64:[function(require,module,exports){ +'use strict'; + +var validate = require('./validate'); +var ValidationError = require('../error/validation_error'); + +module.exports = function validatePaintProperty(options) { + var key = options.key; + var style = options.style; + var styleSpec = options.styleSpec; + var value = options.value; + var propertyKey = options.objectKey; + var layerSpec = styleSpec['paint_' + options.layerType]; + + if (!layerSpec) return []; + + var transitionMatch = propertyKey.match(/^(.*)-transition$/); + + if (transitionMatch && layerSpec[transitionMatch[1]] && layerSpec[transitionMatch[1]].transition) { + return validate({ + key: key, + value: value, + valueSpec: styleSpec.transition, + style: style, + styleSpec: styleSpec + }); + + } else if (options.valueSpec || layerSpec[propertyKey]) { + return validate({ + key: options.key, + value: value, + valueSpec: options.valueSpec || layerSpec[propertyKey], + style: style, + styleSpec: styleSpec + }); + + } else { + return [new ValidationError(key, value, 'unknown property "%s"', propertyKey)]; + } + +}; - // RGBA array - } else if (Array.isArray(input)) { - return input; +},{"../error/validation_error":47,"./validate":51}],65:[function(require,module,exports){ +'use strict'; + +var ValidationError = require('../error/validation_error'); +var unbundle = require('../util/unbundle_jsonlint'); +var validateObject = require('./validate_object'); +var validateEnum = require('./validate_enum'); + +module.exports = function validateSource(options) { + var value = options.value; + var key = options.key; + var styleSpec = options.styleSpec; + var style = options.style; + + if (!value.type) { + return [new ValidationError(key, value, '"type" is required')]; + } + + var type = unbundle(value.type); + switch (type) { + case 'vector': + case 'raster': + var errors = []; + errors = errors.concat(validateObject({ + key: key, + value: value, + valueSpec: styleSpec.source_tile, + style: options.style, + styleSpec: styleSpec + })); + if ('url' in value) { + for (var prop in value) { + if (['type', 'url', 'tileSize'].indexOf(prop) < 0) { + errors.push(new ValidationError(key + '.' + prop, value[prop], 'a source with a "url" property may not include a "%s" property', prop)); + } + } + } + return errors; + + case 'geojson': + return validateObject({ + key: key, + value: value, + valueSpec: styleSpec.source_geojson, + style: style, + styleSpec: styleSpec + }); + + case 'video': + return validateObject({ + key: key, + value: value, + valueSpec: styleSpec.source_video, + style: style, + styleSpec: styleSpec + }); + + case 'image': + return validateObject({ + key: key, + value: value, + valueSpec: styleSpec.source_image, + style: style, + styleSpec: styleSpec + }); + + default: + return validateEnum({ + key: key + '.type', + value: value.type, + valueSpec: {values: ['vector', 'raster', 'geojson', 'video', 'image']}, + style: style, + styleSpec: styleSpec + }); + } +}; - // GL function - } else if (input && input.stops) { - return util.extend({}, input, { - stops: input.stops.map(parseFunctionStopColor) - }); +},{"../error/validation_error":47,"../util/unbundle_jsonlint":50,"./validate_enum":56,"./validate_object":63}],66:[function(require,module,exports){ +'use strict'; + +var getType = require('../util/get_type'); +var ValidationError = require('../error/validation_error'); + +module.exports = function validateString(options) { + var value = options.value; + var key = options.key; + var type = getType(value); + + if (type !== 'string') { + return [new ValidationError(key, value, 'string expected, %s found', type)]; + } + + return []; +}; - // Color string - } else if (typeof input === 'string') { - var parsedColor = parseCSSColor(input); - if (!parsedColor) { throw new Error('Invalid color ' + input); } +},{"../error/validation_error":47,"../util/get_type":49}],67:[function(require,module,exports){ +'use strict'; + +var validateConstants = require('./validate/validate_constants'); +var validate = require('./validate/validate'); +var latestStyleSpec = require('../reference/latest.min'); +var validateGlyphsURL = require('./validate/validate_glyphs_url'); + +/** + * Validate a Mapbox GL style against the style specification. This entrypoint, + * `mapbox-gl-style-spec/lib/validate_style.min`, is designed to produce as + * small a browserify bundle as possible by omitting unnecessary functionality + * and legacy style specifications. + * + * @param {Object} style The style to be validated. + * @param {Object} [styleSpec] The style specification to validate against. + * If omitted, the latest style spec is used. + * @returns {Array} + * @example + * var validate = require('mapbox-gl-style-spec/lib/validate_style.min'); + * var errors = validate(style); + */ +function validateStyleMin(style, styleSpec) { + styleSpec = styleSpec || latestStyleSpec; + + var errors = []; + + errors = errors.concat(validate({ + key: '', + value: style, + valueSpec: styleSpec.$root, + styleSpec: styleSpec, + style: style, + objectElementValidators: { + glyphs: validateGlyphsURL + } + })); + + if (styleSpec.$version > 7 && style.constants) { + errors = errors.concat(validateConstants({ + key: 'constants', + value: style.constants, + style: style, + styleSpec: styleSpec + })); + } + + return sortErrors(errors); +} + +validateStyleMin.source = wrapCleanErrors(require('./validate/validate_source')); +validateStyleMin.layer = wrapCleanErrors(require('./validate/validate_layer')); +validateStyleMin.filter = wrapCleanErrors(require('./validate/validate_filter')); +validateStyleMin.paintProperty = wrapCleanErrors(require('./validate/validate_paint_property')); +validateStyleMin.layoutProperty = wrapCleanErrors(require('./validate/validate_layout_property')); + +function sortErrors(errors) { + return [].concat(errors).sort(function (a, b) { + return a.line - b.line; + }); +} + +function wrapCleanErrors(inner) { + return function() { + return sortErrors(inner.apply(this, arguments)); + }; +} + +module.exports = validateStyleMin; - var output = colorDowngrade(parsedColor); - colorCache[input] = output; - return output; +},{"../reference/latest.min":68,"./validate/validate":51,"./validate/validate_constants":55,"./validate/validate_filter":57,"./validate/validate_glyphs_url":59,"./validate/validate_layer":60,"./validate/validate_layout_property":61,"./validate/validate_paint_property":64,"./validate/validate_source":65}],68:[function(require,module,exports){ +module.exports = require('./v8.min.json'); - } else { - throw new Error('Invalid color ' + input); - } +},{"./v8.min.json":69}],69:[function(require,module,exports){ +module.exports={"$version":8,"$root":{"version":{"required":true,"type":"enum","values":[8]},"name":{"type":"string"},"metadata":{"type":"*"},"center":{"type":"array","value":"number"},"zoom":{"type":"number"},"bearing":{"type":"number","default":0,"period":360,"units":"degrees"},"pitch":{"type":"number","default":0,"units":"degrees"},"sources":{"required":true,"type":"sources"},"sprite":{"type":"string"},"glyphs":{"type":"string"},"transition":{"type":"transition"},"layers":{"required":true,"type":"array","value":"layer"}},"sources":{"*":{"type":"source"}},"source":["source_tile","source_geojson","source_video","source_image"],"source_tile":{"type":{"required":true,"type":"enum","values":["vector","raster"]},"url":{"type":"string"},"tiles":{"type":"array","value":"string"},"minzoom":{"type":"number","default":0},"maxzoom":{"type":"number","default":22},"tileSize":{"type":"number","default":512,"units":"pixels"},"*":{"type":"*"}},"source_geojson":{"type":{"required":true,"type":"enum","values":["geojson"]},"data":{"type":"*"},"maxzoom":{"type":"number","default":18},"buffer":{"type":"number","default":128},"tolerance":{"type":"number","default":0.375},"cluster":{"type":"boolean","default":false},"clusterRadius":{"type":"number","default":50},"clusterMaxZoom":{"type":"number"}},"source_video":{"type":{"required":true,"type":"enum","values":["video"]},"urls":{"required":true,"type":"array","value":"string"},"coordinates":{"required":true,"type":"array","length":4,"value":{"type":"array","length":2,"value":"number"}}},"source_image":{"type":{"required":true,"type":"enum","values":["image"]},"url":{"required":true,"type":"string"},"coordinates":{"required":true,"type":"array","length":4,"value":{"type":"array","length":2,"value":"number"}}},"layer":{"id":{"type":"string","required":true},"type":{"type":"enum","values":["fill","line","symbol","circle","raster","background"]},"metadata":{"type":"*"},"ref":{"type":"string"},"source":{"type":"string"},"source-layer":{"type":"string"},"minzoom":{"type":"number","minimum":0,"maximum":22},"maxzoom":{"type":"number","minimum":0,"maximum":22},"interactive":{"type":"boolean","default":false},"filter":{"type":"filter"},"layout":{"type":"layout"},"paint":{"type":"paint"},"paint.*":{"type":"paint"}},"layout":["layout_fill","layout_line","layout_circle","layout_symbol","layout_raster","layout_background"],"layout_background":{"visibility":{"type":"enum","function":"piecewise-constant","zoom-function":true,"values":["visible","none"],"default":"visible"}},"layout_fill":{"visibility":{"type":"enum","function":"piecewise-constant","zoom-function":true,"values":["visible","none"],"default":"visible"}},"layout_circle":{"visibility":{"type":"enum","function":"piecewise-constant","zoom-function":true,"values":["visible","none"],"default":"visible"}},"layout_line":{"line-cap":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["butt","round","square"],"default":"butt"},"line-join":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["bevel","round","miter"],"default":"miter"},"line-miter-limit":{"type":"number","default":2,"function":"interpolated","zoom-function":true,"property-function":true,"requires":[{"line-join":"miter"}]},"line-round-limit":{"type":"number","default":1.05,"function":"interpolated","zoom-function":true,"property-function":true,"requires":[{"line-join":"round"}]},"visibility":{"type":"enum","function":"piecewise-constant","zoom-function":true,"values":["visible","none"],"default":"visible"}},"layout_symbol":{"symbol-placement":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["point","line"],"default":"point"},"symbol-spacing":{"type":"number","default":250,"minimum":1,"function":"interpolated","zoom-function":true,"property-function":true,"units":"pixels","requires":[{"symbol-placement":"line"}]},"symbol-avoid-edges":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":false},"icon-allow-overlap":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":false,"requires":["icon-image"]},"icon-ignore-placement":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":false,"requires":["icon-image"]},"icon-optional":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":false,"requires":["icon-image","text-field"]},"icon-rotation-alignment":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["map","viewport","auto"],"default":"auto","requires":["icon-image"]},"icon-size":{"type":"number","default":1,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"requires":["icon-image"]},"icon-text-fit":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":false,"values":["none","both","width","height"],"default":"none","requires":["icon-image","text-field"]},"icon-text-fit-padding":{"type":"array","value":"number","length":4,"default":[0,0,0,0],"units":"pixels","function":"interpolated","zoom-function":true,"property-function":true,"requires":["icon-image","icon-text-fit","text-field"]},"icon-image":{"type":"string","function":"piecewise-constant","zoom-function":true,"property-function":true,"tokens":true},"icon-rotate":{"type":"number","default":0,"period":360,"function":"interpolated","zoom-function":true,"property-function":true,"units":"degrees","requires":["icon-image"]},"icon-padding":{"type":"number","default":2,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"units":"pixels","requires":["icon-image"]},"icon-keep-upright":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":false,"requires":["icon-image",{"icon-rotation-alignment":"map"},{"symbol-placement":"line"}]},"icon-offset":{"type":"array","value":"number","length":2,"default":[0,0],"function":"interpolated","zoom-function":true,"property-function":true,"requires":["icon-image"]},"text-pitch-alignment":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["map","viewport","auto"],"default":"auto","requires":["text-field"]},"text-rotation-alignment":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["map","viewport","auto"],"default":"auto","requires":["text-field"]},"text-field":{"type":"string","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":"","tokens":true},"text-font":{"type":"array","value":"string","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":["Open Sans Regular","Arial Unicode MS Regular"],"requires":["text-field"]},"text-size":{"type":"number","default":16,"minimum":0,"units":"pixels","function":"interpolated","zoom-function":true,"property-function":true,"requires":["text-field"]},"text-max-width":{"type":"number","default":10,"minimum":0,"units":"em","function":"interpolated","zoom-function":true,"property-function":true,"requires":["text-field"]},"text-line-height":{"type":"number","default":1.2,"units":"em","function":"interpolated","zoom-function":true,"property-function":true,"requires":["text-field"]},"text-letter-spacing":{"type":"number","default":0,"units":"em","function":"interpolated","zoom-function":true,"property-function":true,"requires":["text-field"]},"text-justify":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["left","center","right"],"default":"center","requires":["text-field"]},"text-anchor":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["center","left","right","top","bottom","top-left","top-right","bottom-left","bottom-right"],"default":"center","requires":["text-field"]},"text-max-angle":{"type":"number","default":45,"units":"degrees","function":"interpolated","zoom-function":true,"property-function":true,"requires":["text-field",{"symbol-placement":"line"}]},"text-rotate":{"type":"number","default":0,"period":360,"units":"degrees","function":"interpolated","zoom-function":true,"property-function":true,"requires":["text-field"]},"text-padding":{"type":"number","default":2,"minimum":0,"units":"pixels","function":"interpolated","zoom-function":true,"property-function":true,"requires":["text-field"]},"text-keep-upright":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":true,"requires":["text-field",{"text-rotation-alignment":"map"},{"symbol-placement":"line"}]},"text-transform":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["none","uppercase","lowercase"],"default":"none","requires":["text-field"]},"text-offset":{"type":"array","value":"number","units":"ems","function":"interpolated","zoom-function":true,"property-function":true,"length":2,"default":[0,0],"requires":["text-field"]},"text-allow-overlap":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":false,"requires":["text-field"]},"text-ignore-placement":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":false,"requires":["text-field"]},"text-optional":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":false,"requires":["text-field","icon-image"]},"visibility":{"type":"enum","function":"piecewise-constant","zoom-function":true,"values":["visible","none"],"default":"visible"}},"layout_raster":{"visibility":{"type":"enum","function":"piecewise-constant","zoom-function":true,"values":["visible","none"],"default":"visible"}},"filter":{"type":"array","value":"*"},"filter_operator":{"type":"enum","values":["==","!=",">",">=","<","<=","in","!in","all","any","none","has","!has"]},"geometry_type":{"type":"enum","values":["Point","LineString","Polygon"]},"color_operation":{"type":"enum","values":["lighten","saturate","spin","fade","mix"]},"function":{"stops":{"type":"array","required":true,"value":"function_stop"},"base":{"type":"number","default":1,"minimum":0},"property":{"type":"string","default":"$zoom"},"type":{"type":"enum","values":["exponential","interval","categorical"],"default":"exponential"}},"function_stop":{"type":"array","minimum":0,"maximum":22,"value":["number","color"],"length":2},"paint":["paint_fill","paint_line","paint_circle","paint_symbol","paint_raster","paint_background"],"paint_fill":{"fill-antialias":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":true},"fill-opacity":{"type":"number","function":"interpolated","zoom-function":true,"property-function":true,"default":1,"minimum":0,"maximum":1,"transition":true},"fill-color":{"type":"color","default":"#000000","function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"requires":[{"!":"fill-pattern"}]},"fill-outline-color":{"type":"color","function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"requires":[{"!":"fill-pattern"},{"fill-antialias":true}]},"fill-translate":{"type":"array","value":"number","length":2,"default":[0,0],"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels"},"fill-translate-anchor":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["map","viewport"],"default":"map","requires":["fill-translate"]},"fill-pattern":{"type":"string","function":"piecewise-constant","zoom-function":true,"property-function":true,"transition":true}},"paint_line":{"line-opacity":{"type":"number","function":"interpolated","zoom-function":true,"property-function":true,"default":1,"minimum":0,"maximum":1,"transition":true},"line-color":{"type":"color","default":"#000000","function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"requires":[{"!":"line-pattern"}]},"line-translate":{"type":"array","value":"number","length":2,"default":[0,0],"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels"},"line-translate-anchor":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["map","viewport"],"default":"map","requires":["line-translate"]},"line-width":{"type":"number","default":1,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels"},"line-gap-width":{"type":"number","default":0,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels"},"line-offset":{"type":"number","default":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels"},"line-blur":{"type":"number","default":0,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels"},"line-dasharray":{"type":"array","value":"number","function":"piecewise-constant","zoom-function":true,"property-function":true,"minimum":0,"transition":true,"units":"line widths","requires":[{"!":"line-pattern"}]},"line-pattern":{"type":"string","function":"piecewise-constant","zoom-function":true,"property-function":true,"transition":true}},"paint_circle":{"circle-radius":{"type":"number","default":5,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels"},"circle-color":{"type":"color","default":"#000000","function":"interpolated","zoom-function":true,"property-function":true,"transition":true},"circle-blur":{"type":"number","default":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true},"circle-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true},"circle-translate":{"type":"array","value":"number","length":2,"default":[0,0],"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels"},"circle-translate-anchor":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["map","viewport"],"default":"map","requires":["circle-translate"]},"circle-pitch-scale":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["map","viewport"],"default":"map"}},"paint_symbol":{"icon-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"requires":["icon-image"]},"icon-color":{"type":"color","default":"#000000","function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"requires":["icon-image"]},"icon-halo-color":{"type":"color","default":"rgba(0, 0, 0, 0)","function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"requires":["icon-image"]},"icon-halo-width":{"type":"number","default":0,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels","requires":["icon-image"]},"icon-halo-blur":{"type":"number","default":0,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels","requires":["icon-image"]},"icon-translate":{"type":"array","value":"number","length":2,"default":[0,0],"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels","requires":["icon-image"]},"icon-translate-anchor":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["map","viewport"],"default":"map","requires":["icon-image","icon-translate"]},"text-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"requires":["text-field"]},"text-color":{"type":"color","default":"#000000","function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"requires":["text-field"]},"text-halo-color":{"type":"color","default":"rgba(0, 0, 0, 0)","function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"requires":["text-field"]},"text-halo-width":{"type":"number","default":0,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels","requires":["text-field"]},"text-halo-blur":{"type":"number","default":0,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels","requires":["text-field"]},"text-translate":{"type":"array","value":"number","length":2,"default":[0,0],"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels","requires":["text-field"]},"text-translate-anchor":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["map","viewport"],"default":"map","requires":["text-field","text-translate"]}},"paint_raster":{"raster-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"function":"interpolated","zoom-function":true,"transition":true},"raster-hue-rotate":{"type":"number","default":0,"period":360,"function":"interpolated","zoom-function":true,"transition":true,"units":"degrees"},"raster-brightness-min":{"type":"number","function":"interpolated","zoom-function":true,"default":0,"minimum":0,"maximum":1,"transition":true},"raster-brightness-max":{"type":"number","function":"interpolated","zoom-function":true,"default":1,"minimum":0,"maximum":1,"transition":true},"raster-saturation":{"type":"number","default":0,"minimum":-1,"maximum":1,"function":"interpolated","zoom-function":true,"transition":true},"raster-contrast":{"type":"number","default":0,"minimum":-1,"maximum":1,"function":"interpolated","zoom-function":true,"transition":true},"raster-fade-duration":{"type":"number","default":300,"minimum":0,"function":"interpolated","zoom-function":true,"transition":true,"units":"milliseconds"}},"paint_background":{"background-color":{"type":"color","default":"#000000","function":"interpolated","zoom-function":true,"transition":true,"requires":[{"!":"background-pattern"}]},"background-pattern":{"type":"string","function":"piecewise-constant","zoom-function":true,"transition":true},"background-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"function":"interpolated","zoom-function":true,"transition":true}},"transition":{"duration":{"type":"number","default":300,"minimum":0,"units":"milliseconds"},"delay":{"type":"number","default":0,"minimum":0,"units":"milliseconds"}}} +},{}],70:[function(require,module,exports){ +'use strict'; +if (typeof module !== 'undefined' && module.exports) { + module.exports = isSupported; +} else if (window) { + window.mapboxgl = window.mapboxgl || {}; + window.mapboxgl.supported = isSupported; } -function parseFunctionStopColor(stop) { - return [stop[0], parseColor(stop[1])]; +/** + * Test whether the current browser supports Mapbox GL JS + * @param {Object} options + * @param {boolean} [options.failIfMajorPerformanceCaveat=false] Return `false` + * if the performance of Mapbox GL JS would be dramatically worse than + * expected (i.e. a software renderer is would be used) + * @return {boolean} + */ +function isSupported(options) { + return !!( + isBrowser() && + isArraySupported() && + isFunctionSupported() && + isObjectSupported() && + isJSONSupported() && + isWorkerSupported() && + isUint8ClampedArraySupported() && + isWebGLSupportedCached(options && options.failIfMajorPerformanceCaveat) + ); } -function colorDowngrade(color) { - return [color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 1]; +function isBrowser() { + return typeof window !== 'undefined' && typeof document !== 'undefined'; } -module.exports = parseColor; - -},{"../util/util":113,"csscolorparser":114}],59:[function(require,module,exports){ -'use strict'; -module.exports = require('mapbox-gl-style-spec/reference/latest'); +function isArraySupported() { + return ( + Array.prototype && + Array.prototype.every && + Array.prototype.filter && + Array.prototype.forEach && + Array.prototype.indexOf && + Array.prototype.lastIndexOf && + Array.prototype.map && + Array.prototype.some && + Array.prototype.reduce && + Array.prototype.reduceRight && + Array.isArray + ); +} -},{"mapbox-gl-style-spec/reference/latest":155}],60:[function(require,module,exports){ -'use strict'; +function isFunctionSupported() { + return Function.prototype && Function.prototype.bind; +} + +function isObjectSupported() { + return ( + Object.keys && + Object.create && + Object.getPrototypeOf && + Object.getOwnPropertyNames && + Object.isSealed && + Object.isFrozen && + Object.isExtensible && + Object.getOwnPropertyDescriptor && + Object.defineProperty && + Object.defineProperties && + Object.seal && + Object.freeze && + Object.preventExtensions + ); +} -var Evented = require('../util/evented'); -var styleBatch = require('./style_batch'); -var StyleLayer = require('./style_layer'); -var ImageSprite = require('./image_sprite'); -var GlyphSource = require('../symbol/glyph_source'); -var SpriteAtlas = require('../symbol/sprite_atlas'); -var LineAtlas = require('../render/line_atlas'); -var util = require('../util/util'); -var ajax = require('../util/ajax'); -var normalizeURL = require('../util/mapbox').normalizeStyleURL; -var browser = require('../util/browser'); -var Dispatcher = require('../util/dispatcher'); -var AnimationLoop = require('./animation_loop'); -var validate = require('mapbox-gl-style-spec/lib/validate/latest'); +function isJSONSupported() { + return 'JSON' in window && 'parse' in JSON && 'stringify' in JSON; +} -module.exports = Style; +function isWorkerSupported() { + return 'Worker' in window; +} -function Style(stylesheet, animationLoop) { - this.animationLoop = animationLoop || new AnimationLoop(); - this.dispatcher = new Dispatcher(Math.max(browser.hardwareConcurrency - 1, 1), this); - this.spriteAtlas = new SpriteAtlas(512, 512); - this.lineAtlas = new LineAtlas(256, 512); +// IE11 only supports `Uint8ClampedArray` as of version +// [KB2929437](https://support.microsoft.com/en-us/kb/2929437) +function isUint8ClampedArraySupported() { + return 'Uint8ClampedArray' in window; +} - this._layers = {}; - this._order = []; - this._groups = []; - this.sources = {}; +var isWebGLSupportedCache = {}; +function isWebGLSupportedCached(failIfMajorPerformanceCaveat) { - this.zoomHistory = {}; + if (isWebGLSupportedCache[failIfMajorPerformanceCaveat] === undefined) { + isWebGLSupportedCache[failIfMajorPerformanceCaveat] = isWebGLSupported(failIfMajorPerformanceCaveat); + } - util.bindAll([ - '_forwardSourceEvent', - '_forwardTileEvent', - '_redoPlacement' - ], this); + return isWebGLSupportedCache[failIfMajorPerformanceCaveat]; +} - var loaded = function(err, stylesheet) { - if (err) { - this.fire('error', {error: err}); - return; - } +isSupported.webGLContextAttributes = { + antialias: false, + alpha: true, + stencil: true, + depth: true +}; - var valid = validate(stylesheet); - if (valid.length) { - for (var i = 0; i < valid.length; i++) { - this.fire('error', { error: new Error(valid[i].message) }); - } - return; - } +function isWebGLSupported(failIfMajorPerformanceCaveat) { - this._loaded = true; - this.stylesheet = stylesheet; + var canvas = document.createElement('canvas'); - var sources = stylesheet.sources; - for (var id in sources) { - this.addSource(id, sources[id]); - } + var attributes = Object.create(isSupported.webGLContextAttributes); + attributes.failIfMajorPerformanceCaveat = failIfMajorPerformanceCaveat; - if (stylesheet.sprite) { - this.sprite = new ImageSprite(stylesheet.sprite); - this.sprite.on('load', this.fire.bind(this, 'change')); - } + if (canvas.probablySupportsContext) { + return ( + canvas.probablySupportsContext('webgl', attributes) || + canvas.probablySupportsContext('experimental-webgl', attributes) + ); - this.glyphSource = new GlyphSource(stylesheet.glyphs); - this._resolve(); - this.fire('load'); - }.bind(this); + } else if (canvas.supportsContext) { + return ( + canvas.supportsContext('webgl', attributes) || + canvas.supportsContext('experimental-webgl', attributes) + ); - if (typeof stylesheet === 'string') { - ajax.getJSON(normalizeURL(stylesheet), loaded); } else { - browser.frame(loaded.bind(this, null, stylesheet)); + return ( + canvas.getContext('webgl', attributes) || + canvas.getContext('experimental-webgl', attributes) + ); } +} - this.on('source.load', function(event) { - var source = event.source; - if (source && source.vectorLayerIds) { - for (var layerId in this._layers) { - var layer = this._layers[layerId]; - if (layer.source === source.id) { - this._validateLayer(layer); - } - } - } +},{}],71:[function(require,module,exports){ +'use strict'; +var util = require('../util/util'); +module.exports = ArrayGroup; +function ArrayGroup(arrayTypes) { + var LayoutVertexArrayType = arrayTypes.layoutVertexArrayType; + this.layoutVertexArray = new LayoutVertexArrayType(); + var ElementArrayType = arrayTypes.elementArrayType; + if (ElementArrayType) + this.elementArray = new ElementArrayType(); + var ElementArrayType2 = arrayTypes.elementArrayType2; + if (ElementArrayType2) + this.elementArray2 = new ElementArrayType2(); + this.paintVertexArrays = util.mapObject(arrayTypes.paintVertexArrayTypes, function (PaintVertexArrayType) { + return new PaintVertexArrayType(); }); } - -Style.prototype = util.inherit(Evented, { - _loaded: false, - - _validateLayer: function(layer) { - var source = this.sources[layer.source]; - - if (!layer.sourceLayer) return; - if (!source) return; - if (!source.vectorLayerIds) return; - - if (source.vectorLayerIds.indexOf(layer.sourceLayer) === -1) { - this.fire('error', { - error: new Error( - 'Source layer "' + layer.sourceLayer + '" ' + - 'does not exist on source "' + source.id + '" ' + - 'as specified by style layer "' + layer.id + '"' - ) - }); - } - }, - - loaded: function() { - if (!this._loaded) - return false; - - for (var id in this.sources) - if (!this.sources[id].loaded()) - return false; - - if (this.sprite && !this.sprite.loaded()) - return false; - - return true; - }, - - _resolve: function() { - var layer, layerJSON; - - this._layers = {}; - this._order = this.stylesheet.layers.map(function(layer) { - return layer.id; +ArrayGroup.MAX_VERTEX_ARRAY_LENGTH = Math.pow(2, 16) - 1; +ArrayGroup.prototype.hasCapacityFor = function (numVertices) { + return this.layoutVertexArray.length + numVertices <= ArrayGroup.MAX_VERTEX_ARRAY_LENGTH; +}; +ArrayGroup.prototype.isEmpty = function () { + return this.layoutVertexArray.length === 0; +}; +ArrayGroup.prototype.trim = function () { + this.layoutVertexArray.trim(); + if (this.elementArray) { + this.elementArray.trim(); + } + if (this.elementArray2) { + this.elementArray2.trim(); + } + for (var layerName in this.paintVertexArrays) { + this.paintVertexArrays[layerName].trim(); + } +}; +ArrayGroup.prototype.serialize = function () { + return { + layoutVertexArray: this.layoutVertexArray.serialize(), + elementArray: this.elementArray && this.elementArray.serialize(), + elementArray2: this.elementArray2 && this.elementArray2.serialize(), + paintVertexArrays: util.mapObject(this.paintVertexArrays, function (array) { + return array.serialize(); + }) + }; +}; +ArrayGroup.prototype.getTransferables = function (transferables) { + transferables.push(this.layoutVertexArray.arrayBuffer); + if (this.elementArray) { + transferables.push(this.elementArray.arrayBuffer); + } + if (this.elementArray2) { + transferables.push(this.elementArray2.arrayBuffer); + } + for (var layerName in this.paintVertexArrays) { + transferables.push(this.paintVertexArrays[layerName].arrayBuffer); + } +}; +},{"../util/util":188}],72:[function(require,module,exports){ +'use strict'; +var ArrayGroup = require('./array_group'); +var BufferGroup = require('./buffer_group'); +var util = require('../util/util'); +var StructArrayType = require('../util/struct_array'); +module.exports = Bucket; +Bucket.create = function (options) { + var Classes = { + fill: require('./bucket/fill_bucket'), + line: require('./bucket/line_bucket'), + circle: require('./bucket/circle_bucket'), + symbol: require('./bucket/symbol_bucket') + }; + return new Classes[options.layer.type](options); +}; +Bucket.EXTENT = 8192; +function Bucket(options) { + this.zoom = options.zoom; + this.overscaling = options.overscaling; + this.layer = options.layer; + this.childLayers = options.childLayers; + this.type = this.layer.type; + this.features = []; + this.id = this.layer.id; + this.index = options.index; + this.sourceLayer = this.layer.sourceLayer; + this.sourceLayerIndex = options.sourceLayerIndex; + this.minZoom = this.layer.minzoom; + this.maxZoom = this.layer.maxzoom; + this.paintAttributes = createPaintAttributes(this); + if (options.arrays) { + var programInterfaces = this.programInterfaces; + this.bufferGroups = util.mapObject(options.arrays, function (programArrayGroups, programName) { + var programInterface = programInterfaces[programName]; + var paintVertexArrayTypes = options.paintVertexArrayTypes[programName]; + return programArrayGroups.map(function (arrayGroup) { + return new BufferGroup(arrayGroup, { + layoutVertexArrayType: programInterface.layoutVertexArrayType.serialize(), + elementArrayType: programInterface.elementArrayType && programInterface.elementArrayType.serialize(), + elementArrayType2: programInterface.elementArrayType2 && programInterface.elementArrayType2.serialize(), + paintVertexArrayTypes: paintVertexArrayTypes + }); + }); }); - - // resolve all layers WITHOUT a ref - for (var i = 0; i < this.stylesheet.layers.length; i++) { - layerJSON = this.stylesheet.layers[i]; - if (layerJSON.ref) continue; - layer = StyleLayer.create(layerJSON); - this._layers[layer.id] = layer; + } +} +Bucket.prototype.populateArrays = function () { + this.createArrays(); + this.recalculateStyleLayers(); + for (var i = 0; i < this.features.length; i++) { + this.addFeature(this.features[i]); + } + this.trimArrays(); +}; +Bucket.prototype.prepareArrayGroup = function (programName, numVertices) { + var groups = this.arrayGroups[programName]; + var currentGroup = groups.length && groups[groups.length - 1]; + if (!currentGroup || !currentGroup.hasCapacityFor(numVertices)) { + currentGroup = new ArrayGroup({ + layoutVertexArrayType: this.programInterfaces[programName].layoutVertexArrayType, + elementArrayType: this.programInterfaces[programName].elementArrayType, + elementArrayType2: this.programInterfaces[programName].elementArrayType2, + paintVertexArrayTypes: this.paintVertexArrayTypes[programName] + }); + currentGroup.index = groups.length; + groups.push(currentGroup); + } + return currentGroup; +}; +Bucket.prototype.createArrays = function () { + this.arrayGroups = {}; + this.paintVertexArrayTypes = {}; + for (var programName in this.programInterfaces) { + this.arrayGroups[programName] = []; + var paintVertexArrayTypes = this.paintVertexArrayTypes[programName] = {}; + var layerPaintAttributes = this.paintAttributes[programName]; + for (var layerName in layerPaintAttributes) { + paintVertexArrayTypes[layerName] = new Bucket.VertexArrayType(layerPaintAttributes[layerName].attributes); } - - // resolve all layers WITH a ref - for (var j = 0; j < this.stylesheet.layers.length; j++) { - layerJSON = this.stylesheet.layers[j]; - if (!layerJSON.ref) continue; - var refLayer = this.getLayer(layerJSON.ref); - layer = StyleLayer.create(layerJSON, refLayer); - this._layers[layer.id] = layer; + } +}; +Bucket.prototype.destroy = function (gl) { + for (var programName in this.bufferGroups) { + var programBufferGroups = this.bufferGroups[programName]; + for (var i = 0; i < programBufferGroups.length; i++) { + programBufferGroups[i].destroy(gl); } - - this._groupLayers(); - this._broadcastLayers(); - }, - - _groupLayers: function() { - var group; - - this._groups = []; - - // Split into groups of consecutive top-level layers with the same source. - for (var i = 0; i < this._order.length; ++i) { - var layer = this._layers[this._order[i]]; - - if (!group || layer.source !== group.source) { - group = []; - group.source = layer.source; - this._groups.push(group); + } +}; +Bucket.prototype.trimArrays = function () { + for (var programName in this.arrayGroups) { + var arrayGroups = this.arrayGroups[programName]; + for (var i = 0; i < arrayGroups.length; i++) { + arrayGroups[i].trim(); + } + } +}; +Bucket.prototype.isEmpty = function () { + for (var programName in this.arrayGroups) { + var arrayGroups = this.arrayGroups[programName]; + for (var i = 0; i < arrayGroups.length; i++) { + if (!arrayGroups[i].isEmpty()) { + return false; } - - group.push(layer); } - }, - - _broadcastLayers: function() { - this.dispatcher.broadcast('set layers', this._order.map(function(id) { - return this._layers[id].serialize({includeRefProperties: true}); - }, this)); - }, - - _cascade: function(classes, options) { - if (!this._loaded) return; - - options = options || { - transition: true - }; - - for (var id in this._layers) { - this._layers[id].cascade(classes, options, - this.stylesheet.transition || {}, - this.animationLoop); + } + return true; +}; +Bucket.prototype.getTransferables = function (transferables) { + for (var programName in this.arrayGroups) { + var arrayGroups = this.arrayGroups[programName]; + for (var i = 0; i < arrayGroups.length; i++) { + arrayGroups[i].getTransferables(transferables); } - - this.fire('change'); - }, - - _recalculate: function(z) { - for (var id in this.sources) - this.sources[id].used = false; - - this._updateZoomHistory(z); - - this.rasterFadeDuration = 300; - for (id in this._layers) { - var layer = this._layers[id]; - - layer.recalculate(z, this.zoomHistory); - if (!layer.isHidden(z) && layer.source) { - this.sources[layer.source].used = true; + } +}; +Bucket.prototype.setUniforms = function (gl, programName, program, layer, globalProperties) { + var uniforms = this.paintAttributes[programName][layer.id].uniforms; + for (var i = 0; i < uniforms.length; i++) { + var uniform = uniforms[i]; + var uniformLocation = program[uniform.name]; + gl['uniform' + uniform.components + 'fv'](uniformLocation, uniform.getValue(layer, globalProperties)); + } +}; +Bucket.prototype.serialize = function () { + return { + layerId: this.layer.id, + zoom: this.zoom, + arrays: util.mapObject(this.arrayGroups, function (programArrayGroups) { + return programArrayGroups.map(function (arrayGroup) { + return arrayGroup.serialize(); + }); + }), + paintVertexArrayTypes: util.mapObject(this.paintVertexArrayTypes, function (arrayTypes) { + return util.mapObject(arrayTypes, function (arrayType) { + return arrayType.serialize(); + }); + }), + childLayerIds: this.childLayers.map(function (layer) { + return layer.id; + }) + }; +}; +var FAKE_ZOOM_HISTORY = { + lastIntegerZoom: Infinity, + lastIntegerZoomTime: 0, + lastZoom: 0 +}; +Bucket.prototype.recalculateStyleLayers = function () { + for (var i = 0; i < this.childLayers.length; i++) { + this.childLayers[i].recalculate(this.zoom, FAKE_ZOOM_HISTORY); + } +}; +Bucket.prototype.populatePaintArrays = function (interfaceName, globalProperties, featureProperties, startGroup, startIndex) { + for (var l = 0; l < this.childLayers.length; l++) { + var layer = this.childLayers[l]; + var groups = this.arrayGroups[interfaceName]; + for (var g = startGroup.index; g < groups.length; g++) { + var group = groups[g]; + var length = group.layoutVertexArray.length; + var paintArray = group.paintVertexArrays[layer.id]; + paintArray.resize(length); + var attributes = this.paintAttributes[interfaceName][layer.id].attributes; + for (var m = 0; m < attributes.length; m++) { + var attribute = attributes[m]; + var value = attribute.getValue(layer, globalProperties, featureProperties); + var multiplier = attribute.multiplier || 1; + var components = attribute.components || 1; + var start = g === startGroup.index ? startIndex : 0; + for (var i = start; i < length; i++) { + var vertex = paintArray.get(i); + for (var c = 0; c < components; c++) { + var memberName = components > 1 ? attribute.name + c : attribute.name; + vertex[memberName] = value[c] * multiplier; + } + } } } - - var maxZoomTransitionDuration = 300; - if (Math.floor(this.z) !== Math.floor(z)) { - this.animationLoop.set(maxZoomTransitionDuration); + } +}; +Bucket.VertexArrayType = function (members) { + return new StructArrayType({ + members: members, + alignment: 4 + }); +}; +Bucket.ElementArrayType = function (components) { + return new StructArrayType({ + members: [{ + type: 'Uint16', + name: 'vertices', + components: components || 3 + }] + }); +}; +function createPaintAttributes(bucket) { + var attributes = {}; + for (var interfaceName in bucket.programInterfaces) { + var layerPaintAttributes = attributes[interfaceName] = {}; + for (var c = 0; c < bucket.childLayers.length; c++) { + var childLayer = bucket.childLayers[c]; + layerPaintAttributes[childLayer.id] = { + attributes: [], + uniforms: [], + defines: [], + vertexPragmas: { + define: {}, + initialize: {} + }, + fragmentPragmas: { + define: {}, + initialize: {} + } + }; } - - this.z = z; - this.fire('zoom'); - }, - - _updateZoomHistory: function(z) { - - var zh = this.zoomHistory; - - if (zh.lastIntegerZoom === undefined) { - // first time - zh.lastIntegerZoom = Math.floor(z); - zh.lastIntegerZoomTime = 0; - zh.lastZoom = z; + var interface_ = bucket.programInterfaces[interfaceName]; + if (!interface_.paintAttributes) + continue; + var attributePrecision = '{precision}'; + var attributeType = '{type}'; + for (var i = 0; i < interface_.paintAttributes.length; i++) { + var attribute = interface_.paintAttributes[i]; + attribute.multiplier = attribute.multiplier || 1; + for (var j = 0; j < bucket.childLayers.length; j++) { + var layer = bucket.childLayers[j]; + var paintAttributes = layerPaintAttributes[layer.id]; + var attributeInputName = attribute.name; + var attributeInnerName = attribute.name.slice(2); + var attributeVaryingDefinition; + paintAttributes.fragmentPragmas.initialize[attributeInnerName] = ''; + if (layer.isPaintValueFeatureConstant(attribute.paintProperty)) { + paintAttributes.uniforms.push(attribute); + paintAttributes.fragmentPragmas.define[attributeInnerName] = paintAttributes.vertexPragmas.define[attributeInnerName] = [ + 'uniform', + attributePrecision, + attributeType, + attributeInputName + ].join(' ') + ';'; + paintAttributes.fragmentPragmas.initialize[attributeInnerName] = paintAttributes.vertexPragmas.initialize[attributeInnerName] = [ + attributePrecision, + attributeType, + attributeInnerName, + '=', + attributeInputName + ].join(' ') + ';\n'; + } else if (layer.isPaintValueZoomConstant(attribute.paintProperty)) { + paintAttributes.attributes.push(util.extend({}, attribute, { name: attributeInputName })); + attributeVaryingDefinition = [ + 'varying', + attributePrecision, + attributeType, + attributeInnerName + ].join(' ') + ';\n'; + var attributeAttributeDefinition = [ + paintAttributes.fragmentPragmas.define[attributeInnerName], + 'attribute', + attributePrecision, + attributeType, + attributeInputName + ].join(' ') + ';\n'; + paintAttributes.fragmentPragmas.define[attributeInnerName] = attributeVaryingDefinition; + paintAttributes.vertexPragmas.define[attributeInnerName] = attributeVaryingDefinition + attributeAttributeDefinition; + paintAttributes.vertexPragmas.initialize[attributeInnerName] = [ + attributeInnerName, + '=', + attributeInputName, + '/', + attribute.multiplier.toFixed(1) + ].join(' ') + ';\n'; + } else { + var tName = 'u_' + attributeInputName.slice(2) + '_t'; + var zoomLevels = layer.getPaintValueStopZoomLevels(attribute.paintProperty); + var numStops = 0; + while (numStops < zoomLevels.length && zoomLevels[numStops] < bucket.zoom) + numStops++; + var stopOffset = Math.max(0, Math.min(zoomLevels.length - 4, numStops - 2)); + var fourZoomLevels = []; + for (var s = 0; s < 4; s++) { + fourZoomLevels.push(zoomLevels[Math.min(stopOffset + s, zoomLevels.length - 1)]); + } + attributeVaryingDefinition = [ + 'varying', + attributePrecision, + attributeType, + attributeInnerName + ].join(' ') + ';\n'; + paintAttributes.vertexPragmas.define[attributeInnerName] = attributeVaryingDefinition + [ + 'uniform', + 'lowp', + 'float', + tName + ].join(' ') + ';\n'; + paintAttributes.fragmentPragmas.define[attributeInnerName] = attributeVaryingDefinition; + paintAttributes.uniforms.push(util.extend({}, attribute, { + name: tName, + getValue: createGetUniform(attribute, stopOffset), + components: 1 + })); + var components = attribute.components; + if (components === 1) { + paintAttributes.attributes.push(util.extend({}, attribute, { + getValue: createFunctionGetValue(attribute, fourZoomLevels), + isFunction: true, + components: components * 4 + })); + paintAttributes.vertexPragmas.define[attributeInnerName] += [ + 'attribute', + attributePrecision, + 'vec4', + attributeInputName + ].join(' ') + ';\n'; + paintAttributes.vertexPragmas.initialize[attributeInnerName] = [ + attributeInnerName, + '=', + 'evaluate_zoom_function_1(' + attributeInputName + ', ' + tName + ')', + '/', + attribute.multiplier.toFixed(1) + ].join(' ') + ';\n'; + } else { + var attributeInputNames = []; + for (var k = 0; k < 4; k++) { + attributeInputNames.push(attributeInputName + k); + paintAttributes.attributes.push(util.extend({}, attribute, { + getValue: createFunctionGetValue(attribute, [fourZoomLevels[k]]), + isFunction: true, + name: attributeInputName + k + })); + paintAttributes.vertexPragmas.define[attributeInnerName] += [ + 'attribute', + attributePrecision, + attributeType, + attributeInputName + k + ].join(' ') + ';\n'; + } + paintAttributes.vertexPragmas.initialize[attributeInnerName] = [ + attributeInnerName, + ' = ', + 'evaluate_zoom_function_4(' + attributeInputNames.join(', ') + ', ' + tName + ')', + '/', + attribute.multiplier.toFixed(1) + ].join(' ') + ';\n'; + } + } + } } - - // check whether an integer zoom level as passed since the last frame - // and if yes, record it with the time. Used for transitioning patterns. - if (Math.floor(zh.lastZoom) < Math.floor(z)) { - zh.lastIntegerZoom = Math.floor(z); - zh.lastIntegerZoomTime = Date.now(); - - } else if (Math.floor(zh.lastZoom) > Math.floor(z)) { - zh.lastIntegerZoom = Math.floor(z + 1); - zh.lastIntegerZoomTime = Date.now(); + } + return attributes; +} +function createFunctionGetValue(attribute, stopZoomLevels) { + return function (layer, globalProperties, featureProperties) { + if (stopZoomLevels.length === 1) { + return attribute.getValue(layer, util.extend({}, globalProperties, { zoom: stopZoomLevels[0] }), featureProperties); + } else { + var values = []; + for (var z = 0; z < stopZoomLevels.length; z++) { + var stopZoomLevel = stopZoomLevels[z]; + values.push(attribute.getValue(layer, util.extend({}, globalProperties, { zoom: stopZoomLevel }), featureProperties)[0]); + } + return values; } - - zh.lastZoom = z; - }, - - /** - * Apply multiple style mutations in a batch - * @param {function} work Function which accepts the StyleBatch interface - * @private - */ - batch: function(work) { - styleBatch(this, work); - }, - - addSource: function(id, source) { - this.batch(function(batch) { - batch.addSource(id, source); - }); - - return this; - }, - - /** - * Remove a source from this stylesheet, given its id. - * @param {string} id id of the source to remove - * @returns {Style} this style - * @throws {Error} if no source is found with the given ID - * @private - */ - removeSource: function(id) { - this.batch(function(batch) { - batch.removeSource(id); - }); - - return this; - }, - - /** - * Get a source by id. - * @param {string} id id of the desired source - * @returns {Object} source - * @private - */ - getSource: function(id) { - return this.sources[id]; - }, - - /** - * Add a layer to the map style. The layer will be inserted before the layer with - * ID `before`, or appended if `before` is omitted. - * @param {StyleLayer|Object} layer - * @param {string=} before ID of an existing layer to insert before - * @fires layer.add - * @returns {Style} `this` - * @private - */ - addLayer: function(layer, before) { - this.batch(function(batch) { - batch.addLayer(layer, before); - }); - - return this; - }, - - /** - * Remove a layer from this stylesheet, given its id. - * @param {string} id id of the layer to remove - * @returns {Style} this style - * @throws {Error} if no layer is found with the given ID - * @private - */ - removeLayer: function(id) { - this.batch(function(batch) { - batch.removeLayer(id); - }); - - return this; - }, - - /** - * Return the style layer object with the given `id`. - * - * @param {string} id - id of the desired layer - * @returns {?Object} a layer, if one with the given `id` exists - * @private - */ - getLayer: function(id) { - return this._layers[id]; - }, - - /** - * If a layer has a `ref` property that makes it derive some values - * from another layer, return that referent layer. Otherwise, - * returns the layer itself. - * @param {string} id the layer's id - * @returns {Layer} the referent layer or the layer itself - * @private - */ - getReferentLayer: function(id) { - var layer = this.getLayer(id); - if (layer.ref) { - layer = this.getLayer(layer.ref); + }; +} +function createGetUniform(attribute, stopOffset) { + return function (layer, globalProperties) { + var stopInterp = layer.getPaintInterpolationT(attribute.paintProperty, globalProperties.zoom); + return [Math.max(0, Math.min(4, stopInterp - stopOffset))]; + }; +} +},{"../util/struct_array":186,"../util/util":188,"./array_group":71,"./bucket/circle_bucket":73,"./bucket/fill_bucket":74,"./bucket/line_bucket":75,"./bucket/symbol_bucket":76,"./buffer_group":78}],73:[function(require,module,exports){ +'use strict'; +var Bucket = require('../bucket'); +var util = require('../../util/util'); +var loadGeometry = require('../load_geometry'); +var EXTENT = Bucket.EXTENT; +module.exports = CircleBucket; +function CircleBucket() { + Bucket.apply(this, arguments); +} +CircleBucket.prototype = util.inherit(Bucket, {}); +CircleBucket.prototype.addCircleVertex = function (layoutVertexArray, x, y, extrudeX, extrudeY) { + return layoutVertexArray.emplaceBack(x * 2 + (extrudeX + 1) / 2, y * 2 + (extrudeY + 1) / 2); +}; +CircleBucket.prototype.programInterfaces = { + circle: { + layoutVertexArrayType: new Bucket.VertexArrayType([{ + name: 'a_pos', + components: 2, + type: 'Int16' + }]), + elementArrayType: new Bucket.ElementArrayType(), + paintAttributes: [ + { + name: 'a_color', + components: 4, + type: 'Uint8', + getValue: function (layer, globalProperties, featureProperties) { + return layer.getPaintValue('circle-color', globalProperties, featureProperties); + }, + multiplier: 255, + paintProperty: 'circle-color' + }, + { + name: 'a_radius', + components: 1, + type: 'Uint16', + isLayerConstant: false, + getValue: function (layer, globalProperties, featureProperties) { + return [layer.getPaintValue('circle-radius', globalProperties, featureProperties)]; + }, + multiplier: 10, + paintProperty: 'circle-radius' + }, + { + name: 'a_blur', + components: 1, + type: 'Uint16', + isLayerConstant: false, + getValue: function (layer, globalProperties, featureProperties) { + return [layer.getPaintValue('circle-blur', globalProperties, featureProperties)]; + }, + multiplier: 10, + paintProperty: 'circle-blur' + }, + { + name: 'a_opacity', + components: 1, + type: 'Uint16', + isLayerConstant: false, + getValue: function (layer, globalProperties, featureProperties) { + return [layer.getPaintValue('circle-opacity', globalProperties, featureProperties)]; + }, + multiplier: 255, + paintProperty: 'circle-opacity' + } + ] + } +}; +CircleBucket.prototype.addFeature = function (feature) { + var globalProperties = { zoom: this.zoom }; + var geometries = loadGeometry(feature); + var startGroup = this.prepareArrayGroup('circle', 0); + var startIndex = startGroup.layoutVertexArray.length; + for (var j = 0; j < geometries.length; j++) { + for (var k = 0; k < geometries[j].length; k++) { + var x = geometries[j][k].x; + var y = geometries[j][k].y; + if (x < 0 || x >= EXTENT || y < 0 || y >= EXTENT) + continue; + var group = this.prepareArrayGroup('circle', 4); + var layoutVertexArray = group.layoutVertexArray; + var index = this.addCircleVertex(layoutVertexArray, x, y, -1, -1); + this.addCircleVertex(layoutVertexArray, x, y, 1, -1); + this.addCircleVertex(layoutVertexArray, x, y, 1, 1); + this.addCircleVertex(layoutVertexArray, x, y, -1, 1); + group.elementArray.emplaceBack(index, index + 1, index + 2); + group.elementArray.emplaceBack(index, index + 3, index + 2); } - return layer; - }, - - setFilter: function(layer, filter) { - this.batch(function(batch) { - batch.setFilter(layer, filter); - }); - - return this; - }, - - setLayerZoomRange: function(layerId, minzoom, maxzoom) { - this.batch(function(batch) { - batch.setLayerZoomRange(layerId, minzoom, maxzoom); - }); - - return this; - }, - - /** - * Get a layer's filter object - * @param {string} layer the layer to inspect - * @returns {*} the layer's filter, if any - * @private - */ - getFilter: function(layer) { - return this.getReferentLayer(layer).filter; - }, - - /** - * Get a layout property's value from a given layer - * @param {string} layer the layer to inspect - * @param {string} name the name of the layout property - * @returns {*} the property value - * @private - */ - getLayoutProperty: function(layer, name) { - return this.getReferentLayer(layer).getLayoutProperty(name); - }, - - getPaintProperty: function(layer, name, klass) { - return this.getLayer(layer).getPaintProperty(name, klass); - }, - - serialize: function() { - return util.filterObject({ - version: this.stylesheet.version, - name: this.stylesheet.name, - metadata: this.stylesheet.metadata, - center: this.stylesheet.center, - zoom: this.stylesheet.zoom, - bearing: this.stylesheet.bearing, - pitch: this.stylesheet.pitch, - sprite: this.stylesheet.sprite, - glyphs: this.stylesheet.glyphs, - transition: this.stylesheet.transition, - sources: util.mapObject(this.sources, function(source) { - return source.serialize(); - }), - layers: this._order.map(function(id) { - return this._layers[id].serialize(); - }, this) - }, function(value) { return value !== undefined; }); - }, - - featuresAt: function(coord, params, callback) { - this._queryFeatures('featuresAt', coord, params, callback); - }, - - featuresIn: function(bbox, params, callback) { - this._queryFeatures('featuresIn', bbox, params, callback); - }, - - _queryFeatures: function(queryType, bboxOrCoords, params, callback) { - var features = []; - var error = null; - - if (params.layer) { - params.layerIds = Array.isArray(params.layer) ? params.layer : [params.layer]; - } - - util.asyncAll(Object.keys(this.sources), function(id, callback) { - var source = this.sources[id]; - source[queryType](bboxOrCoords, params, function(err, result) { - if (result) features = features.concat(result); - if (err) error = err; - callback(); - }); - }.bind(this), function() { - if (error) return callback(error); - - callback(null, features - .filter(function(feature) { - return this._layers[feature.layer] !== undefined; - }.bind(this)) - .map(function(feature) { - feature.layer = this._layers[feature.layer].serialize({ - includeRefProperties: true - }); - return feature; - }.bind(this))); - }.bind(this)); - }, - - _remove: function() { - this.dispatcher.remove(); - }, - - _reloadSource: function(id) { - this.sources[id].reload(); - }, - - _updateSources: function(transform) { - for (var id in this.sources) { - this.sources[id].update(transform); - } - }, - - _redoPlacement: function() { - for (var id in this.sources) { - if (this.sources[id].redoPlacement) this.sources[id].redoPlacement(); - } - }, - - _forwardSourceEvent: function(e) { - this.fire('source.' + e.type, util.extend({source: e.target}, e)); - }, - - _forwardTileEvent: function(e) { - this.fire(e.type, util.extend({source: e.target}, e)); - }, - - // Callbacks from web workers - - 'get sprite json': function(params, callback) { - var sprite = this.sprite; - if (sprite.loaded()) { - callback(null, { sprite: sprite.data, retina: sprite.retina }); - } else { - sprite.on('load', function() { - callback(null, { sprite: sprite.data, retina: sprite.retina }); - }); - } - }, - - 'get icons': function(params, callback) { - var sprite = this.sprite; - var spriteAtlas = this.spriteAtlas; - if (sprite.loaded()) { - spriteAtlas.setSprite(sprite); - spriteAtlas.addIcons(params.icons, callback); - } else { - sprite.on('load', function() { - spriteAtlas.setSprite(sprite); - spriteAtlas.addIcons(params.icons, callback); - }); - } - }, - - 'get glyphs': function(params, callback) { - var stacks = params.stacks, - remaining = Object.keys(stacks).length, - allGlyphs = {}; - - for (var fontName in stacks) { - this.glyphSource.getSimpleGlyphs(fontName, stacks[fontName], params.uid, done); - } - - function done(err, glyphs, fontName) { - if (err) console.error(err); - - allGlyphs[fontName] = glyphs; - remaining--; - - if (remaining === 0) - callback(null, allGlyphs); + } + this.populatePaintArrays('circle', globalProperties, feature.properties, startGroup, startIndex); +}; +},{"../../util/util":188,"../bucket":72,"../load_geometry":80}],74:[function(require,module,exports){ +'use strict'; +var Bucket = require('../bucket'); +var util = require('../../util/util'); +var loadGeometry = require('../load_geometry'); +var earcut = require('earcut'); +var classifyRings = require('../../util/classify_rings'); +var EARCUT_MAX_RINGS = 500; +module.exports = FillBucket; +function FillBucket() { + Bucket.apply(this, arguments); +} +FillBucket.prototype = util.inherit(Bucket, {}); +FillBucket.prototype.programInterfaces = { + fill: { + layoutVertexArrayType: new Bucket.VertexArrayType([{ + name: 'a_pos', + components: 2, + type: 'Int16' + }]), + elementArrayType: new Bucket.ElementArrayType(1), + elementArrayType2: new Bucket.ElementArrayType(2), + paintAttributes: [ + { + name: 'a_color', + components: 4, + type: 'Uint8', + getValue: function (layer, globalProperties, featureProperties) { + return layer.getPaintValue('fill-color', globalProperties, featureProperties); + }, + multiplier: 255, + paintProperty: 'fill-color' + }, + { + name: 'a_outline_color', + components: 4, + type: 'Uint8', + getValue: function (layer, globalProperties, featureProperties) { + return layer.getPaintValue('fill-outline-color', globalProperties, featureProperties); + }, + multiplier: 255, + paintProperty: 'fill-outline-color' + }, + { + name: 'a_opacity', + components: 1, + type: 'Uint8', + getValue: function (layer, globalProperties, featureProperties) { + return [layer.getPaintValue('fill-opacity', globalProperties, featureProperties)]; + }, + multiplier: 255, + paintProperty: 'fill-opacity' + } + ] + } +}; +FillBucket.prototype.addFeature = function (feature) { + var lines = loadGeometry(feature); + var polygons = classifyRings(lines, EARCUT_MAX_RINGS); + var startGroup = this.prepareArrayGroup('fill', 0); + var startIndex = startGroup.layoutVertexArray.length; + for (var i = 0; i < polygons.length; i++) { + this.addPolygon(polygons[i]); + } + this.populatePaintArrays('fill', { zoom: this.zoom }, feature.properties, startGroup, startIndex); +}; +FillBucket.prototype.addPolygon = function (polygon) { + var numVertices = 0; + for (var k = 0; k < polygon.length; k++) { + numVertices += polygon[k].length; + } + var group = this.prepareArrayGroup('fill', numVertices); + var flattened = []; + var holeIndices = []; + var startIndex = group.layoutVertexArray.length; + for (var r = 0; r < polygon.length; r++) { + var ring = polygon[r]; + if (r > 0) + holeIndices.push(flattened.length / 2); + for (var v = 0; v < ring.length; v++) { + var vertex = ring[v]; + var index = group.layoutVertexArray.emplaceBack(vertex.x, vertex.y); + if (v >= 1) { + group.elementArray2.emplaceBack(index - 1, index); + } + flattened.push(vertex.x); + flattened.push(vertex.y); } } -}); - -},{"../render/line_atlas":41,"../symbol/glyph_source":79,"../symbol/sprite_atlas":84,"../util/ajax":101,"../util/browser":102,"../util/dispatcher":104,"../util/evented":107,"../util/mapbox":110,"../util/util":113,"./animation_loop":56,"./image_sprite":57,"./style_batch":61,"./style_layer":63,"mapbox-gl-style-spec/lib/validate/latest":138}],61:[function(require,module,exports){ + var triangleIndices = earcut(flattened, holeIndices); + for (var i = 0; i < triangleIndices.length; i++) { + group.elementArray.emplaceBack(triangleIndices[i] + startIndex); + } +}; +},{"../../util/classify_rings":174,"../../util/util":188,"../bucket":72,"../load_geometry":80,"earcut":11}],75:[function(require,module,exports){ 'use strict'; - -var Source = require('../source/source'); -var StyleLayer = require('./style_layer'); - -function styleBatch(style, work) { - if (!style._loaded) { - throw new Error('Style is not done loading'); +var Bucket = require('../bucket'); +var util = require('../../util/util'); +var loadGeometry = require('../load_geometry'); +var EXTENT = Bucket.EXTENT; +var EXTRUDE_SCALE = 63; +var COS_HALF_SHARP_CORNER = Math.cos(75 / 2 * (Math.PI / 180)); +var SHARP_CORNER_OFFSET = 15; +var LINE_DISTANCE_BUFFER_BITS = 15; +var LINE_DISTANCE_SCALE = 1 / 2; +var MAX_LINE_DISTANCE = Math.pow(2, LINE_DISTANCE_BUFFER_BITS - 1) / LINE_DISTANCE_SCALE; +module.exports = LineBucket; +function LineBucket() { + Bucket.apply(this, arguments); +} +LineBucket.prototype = util.inherit(Bucket, {}); +LineBucket.prototype.addLineVertex = function (layoutVertexBuffer, point, extrude, tx, ty, dir, linesofar) { + return layoutVertexBuffer.emplaceBack(point.x << 1 | tx, point.y << 1 | ty, Math.round(EXTRUDE_SCALE * extrude.x) + 128, Math.round(EXTRUDE_SCALE * extrude.y) + 128, (dir === 0 ? 0 : dir < 0 ? -1 : 1) + 1 | (linesofar * LINE_DISTANCE_SCALE & 63) << 2, linesofar * LINE_DISTANCE_SCALE >> 6); +}; +LineBucket.prototype.programInterfaces = { + line: { + layoutVertexArrayType: new Bucket.VertexArrayType([ + { + name: 'a_pos', + components: 2, + type: 'Int16' + }, + { + name: 'a_data', + components: 4, + type: 'Uint8' + } + ]), + paintAttributes: [{ + name: 'a_color', + components: 4, + type: 'Uint8', + getValue: function (layer, globalProperties, featureProperties) { + return layer.getPaintValue('line-color', globalProperties, featureProperties); + }, + multiplier: 255, + paintProperty: 'line-color' + }], + elementArrayType: new Bucket.ElementArrayType() } - - var batch = Object.create(styleBatch.prototype); - - batch._style = style; - batch._groupLayers = false; - batch._broadcastLayers = false; - batch._reloadSources = {}; - batch._events = []; - batch._change = false; - - work(batch); - - if (batch._groupLayers) { - batch._style._groupLayers(); +}; +LineBucket.prototype.addFeature = function (feature) { + var lines = loadGeometry(feature, LINE_DISTANCE_BUFFER_BITS); + for (var i = 0; i < lines.length; i++) { + this.addLine(lines[i], feature.properties, this.layer.layout['line-join'], this.layer.layout['line-cap'], this.layer.layout['line-miter-limit'], this.layer.layout['line-round-limit']); } - - if (batch._broadcastLayers) { - batch._style._broadcastLayers(); +}; +LineBucket.prototype.addLine = function (vertices, featureProperties, join, cap, miterLimit, roundLimit) { + var len = vertices.length; + while (len > 2 && vertices[len - 1].equals(vertices[len - 2])) { + len--; } - - Object.keys(batch._reloadSources).forEach(function(sourceId) { - batch._style._reloadSource(sourceId); - }); - - batch._events.forEach(function(args) { - batch._style.fire.apply(batch._style, args); - }); - - if (batch._change) { - batch._style.fire('change'); + if (vertices.length < 2) + return; + if (join === 'bevel') + miterLimit = 1.05; + var sharpCornerOffset = SHARP_CORNER_OFFSET * (EXTENT / (512 * this.overscaling)); + var firstVertex = vertices[0], lastVertex = vertices[len - 1], closed = firstVertex.equals(lastVertex); + var group = this.prepareArrayGroup('line', len * 10); + var startIndex = group.layoutVertexArray.length; + if (len === 2 && closed) + return; + this.distance = 0; + var beginCap = cap, endCap = closed ? 'butt' : cap, startOfLine = true, currentVertex, prevVertex, nextVertex, prevNormal, nextNormal, offsetA, offsetB; + this.e1 = this.e2 = this.e3 = -1; + if (closed) { + currentVertex = vertices[len - 2]; + nextNormal = firstVertex.sub(currentVertex)._unit()._perp(); } -} - -styleBatch.prototype = { - - addLayer: function(layer, before) { - if (this._style._layers[layer.id] !== undefined) { - throw new Error('There is already a layer with this ID'); - } - if (!(layer instanceof StyleLayer)) { - var refLayer = layer.ref && this._style.getLayer(layer.ref); - layer = StyleLayer.create(layer, refLayer); - } - this._style._validateLayer(layer); - this._style._layers[layer.id] = layer; - this._style._order.splice(before ? this._style._order.indexOf(before) : Infinity, 0, layer.id); - - this._groupLayers = true; - this._broadcastLayers = true; - if (layer.source) { - this._reloadSources[layer.source] = true; - } - this._events.push(['layer.add', {layer: layer}]); - this._change = true; - - return this; - }, - - removeLayer: function(id) { - var layer = this._style._layers[id]; - if (layer === undefined) { - throw new Error('There is no layer with this ID'); - } - for (var i in this._style._layers) { - if (this._style._layers[i].ref === id) { - this.removeLayer(i); + for (var i = 0; i < len; i++) { + nextVertex = closed && i === len - 1 ? vertices[1] : vertices[i + 1]; + if (nextVertex && vertices[i].equals(nextVertex)) + continue; + if (nextNormal) + prevNormal = nextNormal; + if (currentVertex) + prevVertex = currentVertex; + currentVertex = vertices[i]; + nextNormal = nextVertex ? nextVertex.sub(currentVertex)._unit()._perp() : prevNormal; + prevNormal = prevNormal || nextNormal; + var joinNormal = prevNormal.add(nextNormal)._unit(); + var cosHalfAngle = joinNormal.x * nextNormal.x + joinNormal.y * nextNormal.y; + var miterLength = 1 / cosHalfAngle; + var isSharpCorner = cosHalfAngle < COS_HALF_SHARP_CORNER && prevVertex && nextVertex; + if (isSharpCorner && i > 0) { + var prevSegmentLength = currentVertex.dist(prevVertex); + if (prevSegmentLength > 2 * sharpCornerOffset) { + var newPrevVertex = currentVertex.sub(currentVertex.sub(prevVertex)._mult(sharpCornerOffset / prevSegmentLength)._round()); + this.distance += newPrevVertex.dist(prevVertex); + this.addCurrentVertex(newPrevVertex, this.distance, prevNormal.mult(1), 0, 0, false); + prevVertex = newPrevVertex; } } - delete this._style._layers[id]; - this._style._order.splice(this._style._order.indexOf(id), 1); - - this._groupLayers = true; - this._broadcastLayers = true; - this._events.push(['layer.remove', {layer: layer}]); - this._change = true; - - return this; - }, - - setPaintProperty: function(layer, name, value, klass) { - this._style.getLayer(layer).setPaintProperty(name, value, klass); - this._change = true; - - return this; - }, - - setLayoutProperty: function(layer, name, value) { - layer = this._style.getReferentLayer(layer); - layer.setLayoutProperty(name, value); - - this._broadcastLayers = true; - if (layer.source) { - this._reloadSources[layer.source] = true; - } - this._change = true; - - return this; - }, - - setFilter: function(layer, filter) { - layer = this._style.getReferentLayer(layer); - layer.filter = filter; - - this._broadcastLayers = true; - if (layer.source) { - this._reloadSources[layer.source] = true; - } - this._change = true; - - return this; - }, - - setLayerZoomRange: function(layerId, minzoom, maxzoom) { - var layer = this._style.getReferentLayer(layerId); - if (minzoom != null) { - layer.minzoom = minzoom; + var middleVertex = prevVertex && nextVertex; + var currentJoin = middleVertex ? join : nextVertex ? beginCap : endCap; + if (middleVertex && currentJoin === 'round') { + if (miterLength < roundLimit) { + currentJoin = 'miter'; + } else if (miterLength <= 2) { + currentJoin = 'fakeround'; + } } - if (maxzoom != null) { - layer.maxzoom = maxzoom; + if (currentJoin === 'miter' && miterLength > miterLimit) { + currentJoin = 'bevel'; } - - this._broadcastLayers = true; - if (layer.source) { - this._reloadSources[layer.source] = true; + if (currentJoin === 'bevel') { + if (miterLength > 2) + currentJoin = 'flipbevel'; + if (miterLength < miterLimit) + currentJoin = 'miter'; } - this._change = true; - - return this; - }, - - addSource: function(id, source) { - if (!this._style._loaded) { - throw new Error('Style is not done loading'); + if (prevVertex) + this.distance += currentVertex.dist(prevVertex); + if (currentJoin === 'miter') { + joinNormal._mult(miterLength); + this.addCurrentVertex(currentVertex, this.distance, joinNormal, 0, 0, false); + } else if (currentJoin === 'flipbevel') { + if (miterLength > 100) { + joinNormal = nextNormal.clone(); + } else { + var direction = prevNormal.x * nextNormal.y - prevNormal.y * nextNormal.x > 0 ? -1 : 1; + var bevelLength = miterLength * prevNormal.add(nextNormal).mag() / prevNormal.sub(nextNormal).mag(); + joinNormal._perp()._mult(bevelLength * direction); + } + this.addCurrentVertex(currentVertex, this.distance, joinNormal, 0, 0, false); + this.addCurrentVertex(currentVertex, this.distance, joinNormal.mult(-1), 0, 0, false); + } else if (currentJoin === 'bevel' || currentJoin === 'fakeround') { + var lineTurnsLeft = prevNormal.x * nextNormal.y - prevNormal.y * nextNormal.x > 0; + var offset = -Math.sqrt(miterLength * miterLength - 1); + if (lineTurnsLeft) { + offsetB = 0; + offsetA = offset; + } else { + offsetA = 0; + offsetB = offset; + } + if (!startOfLine) { + this.addCurrentVertex(currentVertex, this.distance, prevNormal, offsetA, offsetB, false); + } + if (currentJoin === 'fakeround') { + var n = Math.floor((0.5 - (cosHalfAngle - 0.5)) * 8); + var approxFractionalJoinNormal; + for (var m = 0; m < n; m++) { + approxFractionalJoinNormal = nextNormal.mult((m + 1) / (n + 1))._add(prevNormal)._unit(); + this.addPieSliceVertex(currentVertex, this.distance, approxFractionalJoinNormal, lineTurnsLeft); + } + this.addPieSliceVertex(currentVertex, this.distance, joinNormal, lineTurnsLeft); + for (var k = n - 1; k >= 0; k--) { + approxFractionalJoinNormal = prevNormal.mult((k + 1) / (n + 1))._add(nextNormal)._unit(); + this.addPieSliceVertex(currentVertex, this.distance, approxFractionalJoinNormal, lineTurnsLeft); + } + } + if (nextVertex) { + this.addCurrentVertex(currentVertex, this.distance, nextNormal, -offsetA, -offsetB, false); + } + } else if (currentJoin === 'butt') { + if (!startOfLine) { + this.addCurrentVertex(currentVertex, this.distance, prevNormal, 0, 0, false); + } + if (nextVertex) { + this.addCurrentVertex(currentVertex, this.distance, nextNormal, 0, 0, false); + } + } else if (currentJoin === 'square') { + if (!startOfLine) { + this.addCurrentVertex(currentVertex, this.distance, prevNormal, 1, 1, false); + this.e1 = this.e2 = -1; + } + if (nextVertex) { + this.addCurrentVertex(currentVertex, this.distance, nextNormal, -1, -1, false); + } + } else if (currentJoin === 'round') { + if (!startOfLine) { + this.addCurrentVertex(currentVertex, this.distance, prevNormal, 0, 0, false); + this.addCurrentVertex(currentVertex, this.distance, prevNormal, 1, 1, true); + this.e1 = this.e2 = -1; + } + if (nextVertex) { + this.addCurrentVertex(currentVertex, this.distance, nextNormal, -1, -1, true); + this.addCurrentVertex(currentVertex, this.distance, nextNormal, 0, 0, false); + } } - if (this._style.sources[id] !== undefined) { - throw new Error('There is already a source with this ID'); + if (isSharpCorner && i < len - 1) { + var nextSegmentLength = currentVertex.dist(nextVertex); + if (nextSegmentLength > 2 * sharpCornerOffset) { + var newCurrentVertex = currentVertex.add(nextVertex.sub(currentVertex)._mult(sharpCornerOffset / nextSegmentLength)._round()); + this.distance += newCurrentVertex.dist(currentVertex); + this.addCurrentVertex(newCurrentVertex, this.distance, nextNormal.mult(1), 0, 0, false); + currentVertex = newCurrentVertex; + } } - source = Source.create(source); - this._style.sources[id] = source; - source.id = id; - source.style = this._style; - source.dispatcher = this._style.dispatcher; - source - .on('load', this._style._forwardSourceEvent) - .on('error', this._style._forwardSourceEvent) - .on('change', this._style._forwardSourceEvent) - .on('tile.add', this._style._forwardTileEvent) - .on('tile.load', this._style._forwardTileEvent) - .on('tile.error', this._style._forwardTileEvent) - .on('tile.remove', this._style._forwardTileEvent) - .on('tile.stats', this._style._forwardTileEvent); - - this._events.push(['source.add', {source: source}]); - this._change = true; - - return this; - }, - - removeSource: function(id) { - if (this._style.sources[id] === undefined) { - throw new Error('There is no source with this ID'); - } - var source = this._style.sources[id]; - delete this._style.sources[id]; - source - .off('load', this._style._forwardSourceEvent) - .off('error', this._style._forwardSourceEvent) - .off('change', this._style._forwardSourceEvent) - .off('tile.add', this._style._forwardTileEvent) - .off('tile.load', this._style._forwardTileEvent) - .off('tile.error', this._style._forwardTileEvent) - .off('tile.remove', this._style._forwardTileEvent) - .off('tile.stats', this._style._forwardTileEvent); - - this._events.push(['source.remove', {source: source}]); - this._change = true; - - return this; + startOfLine = false; } + this.populatePaintArrays('line', { zoom: this.zoom }, featureProperties, group, startIndex); }; - -module.exports = styleBatch; - -},{"../source/source":48,"./style_layer":63}],62:[function(require,module,exports){ -'use strict'; - -var MapboxGLFunction = require('mapbox-gl-function'); -var parseColor = require('./parse_color'); - -module.exports = StyleDeclaration; - -function StyleDeclaration(reference, value) { - this.type = reference.type; - this.transitionable = reference.transition; - this.value = value; - - // immutable representation of value. used for comparison - this.json = JSON.stringify(this.value); - - var parsedValue = this.type === 'color' ? parseColor(this.value) : value; - if (reference.function === 'interpolated') { - this.calculate = MapboxGLFunction.interpolated(parsedValue); - } else { - this.calculate = MapboxGLFunction['piecewise-constant'](parsedValue); - if (reference.transition) { - this.calculate = transitioned(this.calculate); - } +LineBucket.prototype.addCurrentVertex = function (currentVertex, distance, normal, endLeft, endRight, round) { + var tx = round ? 1 : 0; + var extrude; + var arrayGroup = this.arrayGroups.line[this.arrayGroups.line.length - 1]; + var layoutVertexArray = arrayGroup.layoutVertexArray; + var elementArray = arrayGroup.elementArray; + extrude = normal.clone(); + if (endLeft) + extrude._sub(normal.perp()._mult(endLeft)); + this.e3 = this.addLineVertex(layoutVertexArray, currentVertex, extrude, tx, 0, endLeft, distance); + if (this.e1 >= 0 && this.e2 >= 0) { + elementArray.emplaceBack(this.e1, this.e2, this.e3); + } + this.e1 = this.e2; + this.e2 = this.e3; + extrude = normal.mult(-1); + if (endRight) + extrude._sub(normal.perp()._mult(endRight)); + this.e3 = this.addLineVertex(layoutVertexArray, currentVertex, extrude, tx, 1, -endRight, distance); + if (this.e1 >= 0 && this.e2 >= 0) { + elementArray.emplaceBack(this.e1, this.e2, this.e3); + } + this.e1 = this.e2; + this.e2 = this.e3; + if (distance > MAX_LINE_DISTANCE / 2) { + this.distance = 0; + this.addCurrentVertex(currentVertex, this.distance, normal, endLeft, endRight, round); } -} - -function transitioned(calculate) { - return function(z, zh, duration) { - var fraction = z % 1; - var t = Math.min((Date.now() - zh.lastIntegerZoomTime) / duration, 1); - var fromScale = 1; - var toScale = 1; - var mix, from, to; - - if (z > zh.lastIntegerZoom) { - mix = fraction + (1 - fraction) * t; - fromScale *= 2; - from = calculate(z - 1); - to = calculate(z); - } else { - mix = 1 - (1 - t) * fraction; - to = calculate(z); - from = calculate(z + 1); - fromScale /= 2; - } - - return { - from: from, - fromScale: fromScale, - to: to, - toScale: toScale, - t: mix - }; - }; -} - -},{"./parse_color":58,"mapbox-gl-function":133}],63:[function(require,module,exports){ -'use strict'; - -var util = require('../util/util'); -var StyleTransition = require('./style_transition'); -var StyleDeclaration = require('./style_declaration'); -var StyleSpecification = require('./reference'); -var parseColor = require('./parse_color'); - -module.exports = StyleLayer; - -var TRANSITION_SUFFIX = '-transition'; - -StyleLayer.create = function(layer, refLayer) { - var Classes = { - background: require('./style_layer/background_style_layer'), - circle: require('./style_layer/circle_style_layer'), - fill: require('./style_layer/fill_style_layer'), - line: require('./style_layer/line_style_layer'), - raster: require('./style_layer/raster_style_layer'), - symbol: require('./style_layer/symbol_style_layer') - }; - return new Classes[(refLayer || layer).type](layer, refLayer); }; - -function StyleLayer(layer, refLayer) { - this.id = layer.id; - this.ref = layer.ref; - this.metadata = layer.metadata; - this.type = (refLayer || layer).type; - this.source = (refLayer || layer).source; - this.sourceLayer = (refLayer || layer)['source-layer']; - this.minzoom = (refLayer || layer).minzoom; - this.maxzoom = (refLayer || layer).maxzoom; - this.filter = (refLayer || layer).filter; - this.interactive = (refLayer || layer).interactive; - - this._paintSpecifications = StyleSpecification['paint_' + this.type]; - this._layoutSpecifications = StyleSpecification['layout_' + this.type]; - - this._paintTransitions = {}; // {[propertyName]: StyleTransition} - this._paintTransitionOptions = {}; // {[className]: {[propertyName]: { duration:Number, delay:Number }}} - this._paintDeclarations = {}; // {[className]: {[propertyName]: StyleDeclaration}} - this._layoutDeclarations = {}; // {[propertyName]: StyleDeclaration} - - // Resolve paint declarations - for (var key in layer) { - var match = key.match(/^paint(?:\.(.*))?$/); - if (match) { - var klass = match[1] || ''; - for (var name in layer[key]) { - this.setPaintProperty(name, layer[key][name], klass); - } - } +LineBucket.prototype.addPieSliceVertex = function (currentVertex, distance, extrude, lineTurnsLeft) { + var ty = lineTurnsLeft ? 1 : 0; + extrude = extrude.mult(lineTurnsLeft ? -1 : 1); + var arrayGroup = this.arrayGroups.line[this.arrayGroups.line.length - 1]; + var layoutVertexArray = arrayGroup.layoutVertexArray; + var elementArray = arrayGroup.elementArray; + this.e3 = this.addLineVertex(layoutVertexArray, currentVertex, extrude, 0, ty, 0, distance); + if (this.e1 >= 0 && this.e2 >= 0) { + elementArray.emplaceBack(this.e1, this.e2, this.e3); } - - // Resolve layout declarations - if (this.ref) { - this._layoutDeclarations = refLayer._layoutDeclarations; + if (lineTurnsLeft) { + this.e2 = this.e3; } else { - for (name in layer.layout) { - this.setLayoutProperty(name, layer.layout[name]); - } + this.e1 = this.e3; } -} - -StyleLayer.prototype = { - - setLayoutProperty: function(name, value) { - if (value == null) { - delete this._layoutDeclarations[name]; - } else { - this._layoutDeclarations[name] = new StyleDeclaration(this._layoutSpecifications[name], value); - } +}; +},{"../../util/util":188,"../bucket":72,"../load_geometry":80}],76:[function(require,module,exports){ +'use strict'; +var Point = require('point-geometry'); +var Bucket = require('../bucket'); +var Anchor = require('../../symbol/anchor'); +var getAnchors = require('../../symbol/get_anchors'); +var resolveTokens = require('../../util/token'); +var Quads = require('../../symbol/quads'); +var Shaping = require('../../symbol/shaping'); +var resolveText = require('../../symbol/resolve_text'); +var mergeLines = require('../../symbol/mergelines'); +var clipLine = require('../../symbol/clip_line'); +var util = require('../../util/util'); +var loadGeometry = require('../load_geometry'); +var CollisionFeature = require('../../symbol/collision_feature'); +var findPoleOfInaccessibility = require('../../util/find_pole_of_inaccessibility'); +var classifyRings = require('../../util/classify_rings'); +var shapeText = Shaping.shapeText; +var shapeIcon = Shaping.shapeIcon; +var getGlyphQuads = Quads.getGlyphQuads; +var getIconQuads = Quads.getIconQuads; +var EXTENT = Bucket.EXTENT; +module.exports = SymbolBucket; +function SymbolBucket(options) { + Bucket.apply(this, arguments); + this.showCollisionBoxes = options.showCollisionBoxes; + this.overscaling = options.overscaling; + this.collisionBoxArray = options.collisionBoxArray; + this.symbolQuadsArray = options.symbolQuadsArray; + this.symbolInstancesArray = options.symbolInstancesArray; + this.sdfIcons = options.sdfIcons; + this.iconsNeedLinear = options.iconsNeedLinear; + this.adjustedTextSize = options.adjustedTextSize; + this.adjustedIconSize = options.adjustedIconSize; + this.fontstack = options.fontstack; +} +SymbolBucket.MAX_QUADS = 65535; +SymbolBucket.prototype = util.inherit(Bucket, {}); +SymbolBucket.prototype.serialize = function () { + var serialized = Bucket.prototype.serialize.apply(this); + serialized.sdfIcons = this.sdfIcons; + serialized.iconsNeedLinear = this.iconsNeedLinear; + serialized.adjustedTextSize = this.adjustedTextSize; + serialized.adjustedIconSize = this.adjustedIconSize; + serialized.fontstack = this.fontstack; + return serialized; +}; +var layoutVertexArrayType = new Bucket.VertexArrayType([ + { + name: 'a_pos', + components: 2, + type: 'Int16' + }, + { + name: 'a_offset', + components: 2, + type: 'Int16' + }, + { + name: 'a_texture_pos', + components: 2, + type: 'Uint16' + }, + { + name: 'a_data', + components: 4, + type: 'Uint8' + } +]); +var elementArrayType = new Bucket.ElementArrayType(); +function addVertex(array, x, y, ox, oy, tx, ty, minzoom, maxzoom, labelminzoom, labelangle) { + return array.emplaceBack(x, y, Math.round(ox * 64), Math.round(oy * 64), tx / 4, ty / 4, (labelminzoom || 0) * 10, labelangle, (minzoom || 0) * 10, Math.min(maxzoom || 25, 25) * 10); +} +SymbolBucket.prototype.addCollisionBoxVertex = function (layoutVertexArray, point, extrude, maxZoom, placementZoom) { + return layoutVertexArray.emplaceBack(point.x, point.y, Math.round(extrude.x), Math.round(extrude.y), maxZoom * 10, placementZoom * 10); +}; +SymbolBucket.prototype.programInterfaces = { + glyph: { + layoutVertexArrayType: layoutVertexArrayType, + elementArrayType: elementArrayType }, - - getLayoutProperty: function(name) { - return ( - this._layoutDeclarations[name] && - this._layoutDeclarations[name].value - ); + icon: { + layoutVertexArrayType: layoutVertexArrayType, + elementArrayType: elementArrayType }, - - getLayoutValue: function(name, zoom, zoomHistory) { - var specification = this._layoutSpecifications[name]; - var declaration = this._layoutDeclarations[name]; - - if (declaration) { - return declaration.calculate(zoom, zoomHistory); + collisionBox: { + layoutVertexArrayType: new Bucket.VertexArrayType([ + { + name: 'a_pos', + components: 2, + type: 'Int16' + }, + { + name: 'a_extrude', + components: 2, + type: 'Int16' + }, + { + name: 'a_data', + components: 2, + type: 'Uint8' + } + ]) + } +}; +SymbolBucket.prototype.populateArrays = function (collisionTile, stacks, icons) { + var zoomHistory = { + lastIntegerZoom: Infinity, + lastIntegerZoomTime: 0, + lastZoom: 0 + }; + this.adjustedTextMaxSize = this.layer.getLayoutValue('text-size', { + zoom: 18, + zoomHistory: zoomHistory + }); + this.adjustedTextSize = this.layer.getLayoutValue('text-size', { + zoom: this.zoom + 1, + zoomHistory: zoomHistory + }); + this.adjustedIconMaxSize = this.layer.getLayoutValue('icon-size', { + zoom: 18, + zoomHistory: zoomHistory + }); + this.adjustedIconSize = this.layer.getLayoutValue('icon-size', { + zoom: this.zoom + 1, + zoomHistory: zoomHistory + }); + var tileSize = 512 * this.overscaling; + this.tilePixelRatio = EXTENT / tileSize; + this.compareText = {}; + this.iconsNeedLinear = false; + this.symbolInstancesStartIndex = this.symbolInstancesArray.length; + var layout = this.layer.layout; + var features = this.features; + var textFeatures = this.textFeatures; + var horizontalAlign = 0.5, verticalAlign = 0.5; + switch (layout['text-anchor']) { + case 'right': + case 'top-right': + case 'bottom-right': + horizontalAlign = 1; + break; + case 'left': + case 'top-left': + case 'bottom-left': + horizontalAlign = 0; + break; + } + switch (layout['text-anchor']) { + case 'bottom': + case 'bottom-right': + case 'bottom-left': + verticalAlign = 1; + break; + case 'top': + case 'top-right': + case 'top-left': + verticalAlign = 0; + break; + } + var justify = layout['text-justify'] === 'right' ? 1 : layout['text-justify'] === 'left' ? 0 : 0.5; + var oneEm = 24; + var lineHeight = layout['text-line-height'] * oneEm; + var maxWidth = layout['symbol-placement'] !== 'line' ? layout['text-max-width'] * oneEm : 0; + var spacing = layout['text-letter-spacing'] * oneEm; + var textOffset = [ + layout['text-offset'][0] * oneEm, + layout['text-offset'][1] * oneEm + ]; + var fontstack = this.fontstack = layout['text-font'].join(','); + var geometries = []; + for (var g = 0; g < features.length; g++) { + geometries.push(loadGeometry(features[g])); + } + if (layout['symbol-placement'] === 'line') { + var merged = mergeLines(features, textFeatures, geometries); + geometries = merged.geometries; + features = merged.features; + textFeatures = merged.textFeatures; + } + var shapedText, shapedIcon; + for (var k = 0; k < features.length; k++) { + if (!geometries[k]) + continue; + if (textFeatures[k]) { + shapedText = shapeText(textFeatures[k], stacks[fontstack], maxWidth, lineHeight, horizontalAlign, verticalAlign, justify, spacing, textOffset); } else { - return specification.default; + shapedText = null; } - }, - - setPaintProperty: function(name, value, klass) { - if (util.endsWith(name, TRANSITION_SUFFIX)) { - if (!this._paintTransitionOptions[klass || '']) { - this._paintTransitionOptions[klass || ''] = {}; - } - if (value === null || value === undefined) { - delete this._paintTransitionOptions[klass || ''][name]; - } else { - this._paintTransitionOptions[klass || ''][name] = value; + if (layout['icon-image']) { + var iconName = resolveTokens(features[k].properties, layout['icon-image']); + var image = icons[iconName]; + shapedIcon = shapeIcon(image, layout); + if (image) { + if (this.sdfIcons === undefined) { + this.sdfIcons = image.sdf; + } else if (this.sdfIcons !== image.sdf) { + util.warnOnce('Style sheet warning: Cannot mix SDF and non-SDF icons in one buffer'); + } + if (image.pixelRatio !== 1) { + this.iconsNeedLinear = true; + } else if (layout['icon-rotate'] !== 0 || !this.layer.isLayoutValueFeatureConstant('icon-rotate')) { + this.iconsNeedLinear = true; + } } } else { - if (!this._paintDeclarations[klass || '']) { - this._paintDeclarations[klass || ''] = {}; - } - if (value === null || value === undefined) { - delete this._paintDeclarations[klass || ''][name]; - } else { - this._paintDeclarations[klass || ''][name] = new StyleDeclaration(this._paintSpecifications[name], value); - } + shapedIcon = null; } - }, - - getPaintProperty: function(name, klass) { - klass = klass || ''; - if (util.endsWith(name, TRANSITION_SUFFIX)) { - return ( - this._paintTransitionOptions[klass] && - this._paintTransitionOptions[klass][name] - ); - } else { - return ( - this._paintDeclarations[klass] && - this._paintDeclarations[klass][name] && - this._paintDeclarations[klass][name].value - ); + if (shapedText || shapedIcon) { + this.addFeature(geometries[k], shapedText, shapedIcon, features[k]); } - }, - - getPaintValue: function(name, zoom, zoomHistory) { - var specification = this._paintSpecifications[name]; - var transition = this._paintTransitions[name]; - - if (transition) { - return transition.at(zoom, zoomHistory); - } else if (specification.type === 'color' && specification.default) { - return parseColor(specification.default); + } + this.symbolInstancesEndIndex = this.symbolInstancesArray.length; + this.placeFeatures(collisionTile, this.showCollisionBoxes); + this.trimArrays(); +}; +SymbolBucket.prototype.addFeature = function (lines, shapedText, shapedIcon, feature) { + var layout = this.layer.layout; + var glyphSize = 24; + var fontScale = this.adjustedTextSize / glyphSize, textMaxSize = this.adjustedTextMaxSize !== undefined ? this.adjustedTextMaxSize : this.adjustedTextSize, textBoxScale = this.tilePixelRatio * fontScale, textMaxBoxScale = this.tilePixelRatio * textMaxSize / glyphSize, iconBoxScale = this.tilePixelRatio * this.adjustedIconSize, symbolMinDistance = this.tilePixelRatio * layout['symbol-spacing'], avoidEdges = layout['symbol-avoid-edges'], textPadding = layout['text-padding'] * this.tilePixelRatio, iconPadding = layout['icon-padding'] * this.tilePixelRatio, textMaxAngle = layout['text-max-angle'] / 180 * Math.PI, textAlongLine = layout['text-rotation-alignment'] === 'map' && layout['symbol-placement'] === 'line', iconAlongLine = layout['icon-rotation-alignment'] === 'map' && layout['symbol-placement'] === 'line', mayOverlap = layout['text-allow-overlap'] || layout['icon-allow-overlap'] || layout['text-ignore-placement'] || layout['icon-ignore-placement'], symbolPlacement = layout['symbol-placement'], isLine = symbolPlacement === 'line', textRepeatDistance = symbolMinDistance / 2; + var list = null; + if (isLine) { + list = clipLine(lines, 0, 0, EXTENT, EXTENT); + } else { + list = classifyRings(lines, 0); + } + for (var i = 0; i < list.length; i++) { + var anchors = null; + var pointsOrRings = list[i]; + var line = null; + if (isLine) { + line = pointsOrRings; + anchors = getAnchors(line, symbolMinDistance, textMaxAngle, shapedText, shapedIcon, glyphSize, textMaxBoxScale, this.overscaling, EXTENT); } else { - return specification.default; + line = pointsOrRings[0]; + anchors = this.findPolygonAnchors(pointsOrRings); } - }, - - isHidden: function(zoom) { - if (this.minzoom && zoom < this.minzoom) return true; - if (this.maxzoom && zoom >= this.maxzoom) return true; - - if (this.getLayoutValue('visibility') === 'none') return true; - - var opacityProperty = this.type + '-opacity'; - if (this._paintSpecifications[opacityProperty] && this.getPaintValue(opacityProperty) === 0) return true; - - return false; - }, - - // update classes - cascade: function(classes, options, globalTransitionOptions, animationLoop) { - var oldTransitions = this._paintTransitions; - var newTransitions = this._paintTransitions = {}; - var that = this; - - // Apply new declarations in all active classes - for (var klass in this._paintDeclarations) { - if (klass !== "" && !classes[klass]) continue; - for (var name in this._paintDeclarations[klass]) { - applyDeclaration(this._paintDeclarations[klass][name]); + for (var j = 0, len = anchors.length; j < len; j++) { + var anchor = anchors[j]; + if (shapedText && isLine) { + if (this.anchorIsTooClose(shapedText.text, textRepeatDistance, anchor)) { + continue; + } } + var inside = !(anchor.x < 0 || anchor.x > EXTENT || anchor.y < 0 || anchor.y > EXTENT); + if (avoidEdges && !inside) + continue; + var addToBuffers = inside || mayOverlap; + this.addSymbolInstance(anchor, line, shapedText, shapedIcon, this.layer, addToBuffers, this.symbolInstancesArray.length, this.collisionBoxArray, feature.index, this.sourceLayerIndex, this.index, textBoxScale, textPadding, textAlongLine, iconBoxScale, iconPadding, iconAlongLine, { zoom: this.zoom }, feature.properties); } - - // Apply removed declarations - var removedNames = util.keysDifference(oldTransitions, newTransitions); - for (var i = 0; i < removedNames.length; i++) { - var spec = this._paintSpecifications[removedNames[i]]; - applyDeclaration(new StyleDeclaration(spec, spec.default)); - } - - function applyDeclaration(declaration) { - var oldTransition = options.transition ? oldTransitions[name] : undefined; - - if (oldTransition && oldTransition.declaration.json === declaration.json) { - newTransitions[name] = oldTransition; - - } else { - var newTransition = new StyleTransition(declaration, oldTransition, util.extend( - {duration: 300, delay: 0}, - globalTransitionOptions, - that.getPaintProperty(name + TRANSITION_SUFFIX) - )); - - if (!newTransition.instant()) { - newTransition.loopID = animationLoop.set(newTransition.endTime - (new Date()).getTime()); - } - - if (oldTransition) { - animationLoop.cancel(oldTransition.loopID); - } - - newTransitions[name] = newTransition; + } +}; +SymbolBucket.prototype.findPolygonAnchors = function (polygonRings) { + var outerRing = polygonRings[0]; + if (outerRing.length === 0) { + return []; + } else if (outerRing.length < 3 || !util.isClosedPolygon(outerRing)) { + return [new Anchor(outerRing[0].x, outerRing[0].y, 0)]; + } + var anchors = null; + var poi = findPoleOfInaccessibility(polygonRings, 16); + anchors = [new Anchor(poi.x, poi.y, 0)]; + return anchors; +}; +SymbolBucket.prototype.anchorIsTooClose = function (text, repeatDistance, anchor) { + var compareText = this.compareText; + if (!(text in compareText)) { + compareText[text] = []; + } else { + var otherAnchors = compareText[text]; + for (var k = otherAnchors.length - 1; k >= 0; k--) { + if (anchor.dist(otherAnchors[k]) < repeatDistance) { + return true; } } - }, - - // update zoom - recalculate: function(zoom, zoomHistory) { - this.paint = {}; - for (var name in this._paintSpecifications) { - this.paint[name] = this.getPaintValue(name, zoom, zoomHistory); + } + compareText[text].push(anchor); + return false; +}; +SymbolBucket.prototype.placeFeatures = function (collisionTile, showCollisionBoxes) { + this.recalculateStyleLayers(); + this.createArrays(); + var layout = this.layer.layout; + var maxScale = collisionTile.maxScale; + var textAlongLine = layout['text-rotation-alignment'] === 'map' && layout['symbol-placement'] === 'line'; + var iconAlongLine = layout['icon-rotation-alignment'] === 'map' && layout['symbol-placement'] === 'line'; + var mayOverlap = layout['text-allow-overlap'] || layout['icon-allow-overlap'] || layout['text-ignore-placement'] || layout['icon-ignore-placement']; + if (mayOverlap) { + var symbolInstancesStructTypeArray = this.symbolInstancesArray.toArray(this.symbolInstancesStartIndex, this.symbolInstancesEndIndex); + var angle = collisionTile.angle; + var sin = Math.sin(angle), cos = Math.cos(angle); + this.sortedSymbolInstances = symbolInstancesStructTypeArray.sort(function (a, b) { + var aRotated = sin * a.anchorPointX + cos * a.anchorPointY | 0; + var bRotated = sin * b.anchorPointX + cos * b.anchorPointY | 0; + return aRotated - bRotated || b.index - a.index; + }); + } + for (var p = this.symbolInstancesStartIndex; p < this.symbolInstancesEndIndex; p++) { + var symbolInstance = this.sortedSymbolInstances ? this.sortedSymbolInstances[p - this.symbolInstancesStartIndex] : this.symbolInstancesArray.get(p); + var textCollisionFeature = { + boxStartIndex: symbolInstance.textBoxStartIndex, + boxEndIndex: symbolInstance.textBoxEndIndex + }; + var iconCollisionFeature = { + boxStartIndex: symbolInstance.iconBoxStartIndex, + boxEndIndex: symbolInstance.iconBoxEndIndex + }; + var hasText = !(symbolInstance.textBoxStartIndex === symbolInstance.textBoxEndIndex); + var hasIcon = !(symbolInstance.iconBoxStartIndex === symbolInstance.iconBoxEndIndex); + var iconWithoutText = layout['text-optional'] || !hasText, textWithoutIcon = layout['icon-optional'] || !hasIcon; + var glyphScale = hasText ? collisionTile.placeCollisionFeature(textCollisionFeature, layout['text-allow-overlap'], layout['symbol-avoid-edges']) : collisionTile.minScale; + var iconScale = hasIcon ? collisionTile.placeCollisionFeature(iconCollisionFeature, layout['icon-allow-overlap'], layout['symbol-avoid-edges']) : collisionTile.minScale; + if (!iconWithoutText && !textWithoutIcon) { + iconScale = glyphScale = Math.max(iconScale, glyphScale); + } else if (!textWithoutIcon && glyphScale) { + glyphScale = Math.max(iconScale, glyphScale); + } else if (!iconWithoutText && iconScale) { + iconScale = Math.max(iconScale, glyphScale); } - - this.layout = {}; - for (name in this._layoutSpecifications) { - this.layout[name] = this.getLayoutValue(name, zoom, zoomHistory); + if (hasText) { + collisionTile.insertCollisionFeature(textCollisionFeature, glyphScale, layout['text-ignore-placement']); + if (glyphScale <= maxScale) { + this.addSymbols('glyph', symbolInstance.glyphQuadStartIndex, symbolInstance.glyphQuadEndIndex, glyphScale, layout['text-keep-upright'], textAlongLine, collisionTile.angle); + } } - }, - - serialize: function(options) { - var output = { - 'id': this.id, - 'ref': this.ref, - 'metadata': this.metadata, - 'minzoom': this.minzoom, - 'maxzoom': this.maxzoom, - 'interactive': this.interactive - }; - - for (var klass in this._paintDeclarations) { - var key = klass === '' ? 'paint' : 'paint.' + key; - output[key] = util.mapObject(this._paintDeclarations[klass], getDeclarationValue); + if (hasIcon) { + collisionTile.insertCollisionFeature(iconCollisionFeature, iconScale, layout['icon-ignore-placement']); + if (iconScale <= maxScale) { + this.addSymbols('icon', symbolInstance.iconQuadStartIndex, symbolInstance.iconQuadEndIndex, iconScale, layout['icon-keep-upright'], iconAlongLine, collisionTile.angle); + } } - - if (!this.ref || (options && options.includeRefProperties)) { - util.extend(output, { - 'type': this.type, - 'source': this.source, - 'source-layer': this.sourceLayer, - 'filter': this.filter, - 'layout': util.mapObject(this._layoutDeclarations, getDeclarationValue) - }); + } + if (showCollisionBoxes) + this.addToDebugBuffers(collisionTile); +}; +SymbolBucket.prototype.addSymbols = function (programName, quadsStart, quadsEnd, scale, keepUpright, alongLine, placementAngle) { + var group = this.prepareArrayGroup(programName, 4 * (quadsEnd - quadsStart)); + var elementArray = group.elementArray; + var layoutVertexArray = group.layoutVertexArray; + var zoom = this.zoom; + var placementZoom = Math.max(Math.log(scale) / Math.LN2 + zoom, 0); + for (var k = quadsStart; k < quadsEnd; k++) { + var symbol = this.symbolQuadsArray.get(k).SymbolQuad; + var a = (symbol.anchorAngle + placementAngle + Math.PI) % (Math.PI * 2); + if (keepUpright && alongLine && (a <= Math.PI / 2 || a > Math.PI * 3 / 2)) + continue; + var tl = symbol.tl, tr = symbol.tr, bl = symbol.bl, br = symbol.br, tex = symbol.tex, anchorPoint = symbol.anchorPoint, minZoom = Math.max(zoom + Math.log(symbol.minScale) / Math.LN2, placementZoom), maxZoom = Math.min(zoom + Math.log(symbol.maxScale) / Math.LN2, 25); + if (maxZoom <= minZoom) + continue; + if (minZoom === placementZoom) + minZoom = 0; + var glyphAngle = Math.round(symbol.glyphAngle / (Math.PI * 2) * 256); + var index = addVertex(layoutVertexArray, anchorPoint.x, anchorPoint.y, tl.x, tl.y, tex.x, tex.y, minZoom, maxZoom, placementZoom, glyphAngle); + addVertex(layoutVertexArray, anchorPoint.x, anchorPoint.y, tr.x, tr.y, tex.x + tex.w, tex.y, minZoom, maxZoom, placementZoom, glyphAngle); + addVertex(layoutVertexArray, anchorPoint.x, anchorPoint.y, bl.x, bl.y, tex.x, tex.y + tex.h, minZoom, maxZoom, placementZoom, glyphAngle); + addVertex(layoutVertexArray, anchorPoint.x, anchorPoint.y, br.x, br.y, tex.x + tex.w, tex.y + tex.h, minZoom, maxZoom, placementZoom, glyphAngle); + elementArray.emplaceBack(index, index + 1, index + 2); + elementArray.emplaceBack(index + 1, index + 2, index + 3); + } +}; +SymbolBucket.prototype.updateIcons = function (icons) { + this.recalculateStyleLayers(); + var iconValue = this.layer.layout['icon-image']; + if (!iconValue) + return; + for (var i = 0; i < this.features.length; i++) { + var iconName = resolveTokens(this.features[i].properties, iconValue); + if (iconName) + icons[iconName] = true; + } +}; +SymbolBucket.prototype.updateFont = function (stacks) { + this.recalculateStyleLayers(); + var fontName = this.layer.layout['text-font'], stack = stacks[fontName] = stacks[fontName] || {}; + this.textFeatures = resolveText(this.features, this.layer.layout, stack); +}; +SymbolBucket.prototype.addToDebugBuffers = function (collisionTile) { + var group = this.prepareArrayGroup('collisionBox', 0); + var layoutVertexArray = group.layoutVertexArray; + var angle = -collisionTile.angle; + var yStretch = collisionTile.yStretch; + for (var j = this.symbolInstancesStartIndex; j < this.symbolInstancesEndIndex; j++) { + var symbolInstance = this.symbolInstancesArray.get(j); + symbolInstance.textCollisionFeature = { + boxStartIndex: symbolInstance.textBoxStartIndex, + boxEndIndex: symbolInstance.textBoxEndIndex + }; + symbolInstance.iconCollisionFeature = { + boxStartIndex: symbolInstance.iconBoxStartIndex, + boxEndIndex: symbolInstance.iconBoxEndIndex + }; + for (var i = 0; i < 2; i++) { + var feature = symbolInstance[i === 0 ? 'textCollisionFeature' : 'iconCollisionFeature']; + if (!feature) + continue; + for (var b = feature.boxStartIndex; b < feature.boxEndIndex; b++) { + var box = this.collisionBoxArray.get(b); + var anchorPoint = box.anchorPoint; + var tl = new Point(box.x1, box.y1 * yStretch)._rotate(angle); + var tr = new Point(box.x2, box.y1 * yStretch)._rotate(angle); + var bl = new Point(box.x1, box.y2 * yStretch)._rotate(angle); + var br = new Point(box.x2, box.y2 * yStretch)._rotate(angle); + var maxZoom = Math.max(0, Math.min(25, this.zoom + Math.log(box.maxScale) / Math.LN2)); + var placementZoom = Math.max(0, Math.min(25, this.zoom + Math.log(box.placementScale) / Math.LN2)); + this.addCollisionBoxVertex(layoutVertexArray, anchorPoint, tl, maxZoom, placementZoom); + this.addCollisionBoxVertex(layoutVertexArray, anchorPoint, tr, maxZoom, placementZoom); + this.addCollisionBoxVertex(layoutVertexArray, anchorPoint, tr, maxZoom, placementZoom); + this.addCollisionBoxVertex(layoutVertexArray, anchorPoint, br, maxZoom, placementZoom); + this.addCollisionBoxVertex(layoutVertexArray, anchorPoint, br, maxZoom, placementZoom); + this.addCollisionBoxVertex(layoutVertexArray, anchorPoint, bl, maxZoom, placementZoom); + this.addCollisionBoxVertex(layoutVertexArray, anchorPoint, bl, maxZoom, placementZoom); + this.addCollisionBoxVertex(layoutVertexArray, anchorPoint, tl, maxZoom, placementZoom); + } } - - return util.filterObject(output, function(value, key) { - return value !== undefined && !(key === 'layout' && !Object.keys(value).length); - }); } }; - -function getDeclarationValue(declaration) { - return declaration.value; -} - -},{"../util/util":113,"./parse_color":58,"./reference":59,"./style_declaration":62,"./style_layer/background_style_layer":64,"./style_layer/circle_style_layer":65,"./style_layer/fill_style_layer":66,"./style_layer/line_style_layer":67,"./style_layer/raster_style_layer":68,"./style_layer/symbol_style_layer":69,"./style_transition":70}],64:[function(require,module,exports){ -'use strict'; - -var util = require('../../util/util'); -var StyleLayer = require('../style_layer'); - -function BackgroundStyleLayer() { - StyleLayer.apply(this, arguments); -} - -module.exports = BackgroundStyleLayer; - -BackgroundStyleLayer.prototype = util.inherit(StyleLayer, {}); - -},{"../../util/util":113,"../style_layer":63}],65:[function(require,module,exports){ -'use strict'; - -var util = require('../../util/util'); -var StyleLayer = require('../style_layer'); - -function CircleStyleLayer() { - StyleLayer.apply(this, arguments); -} - -module.exports = CircleStyleLayer; - -CircleStyleLayer.prototype = util.inherit(StyleLayer, {}); - -},{"../../util/util":113,"../style_layer":63}],66:[function(require,module,exports){ -'use strict'; - -var util = require('../../util/util'); -var StyleLayer = require('../style_layer'); - -function FillStyleLayer() { - StyleLayer.apply(this, arguments); -} - -module.exports = FillStyleLayer; - -FillStyleLayer.prototype = util.inherit(StyleLayer, {}); - -},{"../../util/util":113,"../style_layer":63}],67:[function(require,module,exports){ -'use strict'; - -var util = require('../../util/util'); -var StyleLayer = require('../style_layer'); - -function LineStyleLayer() { - StyleLayer.apply(this, arguments); -} - -module.exports = LineStyleLayer; - -LineStyleLayer.prototype = util.inherit(StyleLayer, { - - getPaintValue: function(name, zoom) { - var output = StyleLayer.prototype.getPaintValue.apply(this, arguments); - - // If the line is dashed, scale the dash lengths by the line - // width at the previous round zoom level. - if (output && name === 'line-dasharray') { - var lineWidth = this.getPaintValue('line-width', Math.floor(zoom), Infinity); - output.fromScale *= lineWidth; - output.toScale *= lineWidth; +SymbolBucket.prototype.addSymbolInstance = function (anchor, line, shapedText, shapedIcon, layer, addToBuffers, index, collisionBoxArray, featureIndex, sourceLayerIndex, bucketIndex, textBoxScale, textPadding, textAlongLine, iconBoxScale, iconPadding, iconAlongLine, globalProperties, featureProperties) { + var glyphQuadStartIndex, glyphQuadEndIndex, iconQuadStartIndex, iconQuadEndIndex, textCollisionFeature, iconCollisionFeature, glyphQuads, iconQuads; + if (shapedText) { + glyphQuads = addToBuffers ? getGlyphQuads(anchor, shapedText, textBoxScale, line, layer, textAlongLine) : []; + textCollisionFeature = new CollisionFeature(collisionBoxArray, line, anchor, featureIndex, sourceLayerIndex, bucketIndex, shapedText, textBoxScale, textPadding, textAlongLine, false); + } + glyphQuadStartIndex = this.symbolQuadsArray.length; + if (glyphQuads && glyphQuads.length) { + for (var i = 0; i < glyphQuads.length; i++) { + this.addSymbolQuad(glyphQuads[i]); } - - return output; } - -}); - -},{"../../util/util":113,"../style_layer":63}],68:[function(require,module,exports){ -'use strict'; - -var util = require('../../util/util'); -var StyleLayer = require('../style_layer'); - -function RasterStyleLayer() { - StyleLayer.apply(this, arguments); -} - -module.exports = RasterStyleLayer; - -RasterStyleLayer.prototype = util.inherit(StyleLayer, {}); - -},{"../../util/util":113,"../style_layer":63}],69:[function(require,module,exports){ + glyphQuadEndIndex = this.symbolQuadsArray.length; + var textBoxStartIndex = textCollisionFeature ? textCollisionFeature.boxStartIndex : this.collisionBoxArray.length; + var textBoxEndIndex = textCollisionFeature ? textCollisionFeature.boxEndIndex : this.collisionBoxArray.length; + if (shapedIcon) { + iconQuads = addToBuffers ? getIconQuads(anchor, shapedIcon, iconBoxScale, line, layer, iconAlongLine, shapedText, globalProperties, featureProperties) : []; + iconCollisionFeature = new CollisionFeature(collisionBoxArray, line, anchor, featureIndex, sourceLayerIndex, bucketIndex, shapedIcon, iconBoxScale, iconPadding, iconAlongLine, true); + } + iconQuadStartIndex = this.symbolQuadsArray.length; + if (iconQuads && iconQuads.length === 1) { + this.addSymbolQuad(iconQuads[0]); + } + iconQuadEndIndex = this.symbolQuadsArray.length; + var iconBoxStartIndex = iconCollisionFeature ? iconCollisionFeature.boxStartIndex : this.collisionBoxArray.length; + var iconBoxEndIndex = iconCollisionFeature ? iconCollisionFeature.boxEndIndex : this.collisionBoxArray.length; + if (iconQuadEndIndex > SymbolBucket.MAX_QUADS) + util.warnOnce('Too many symbols being rendered in a tile. See https://github.com/mapbox/mapbox-gl-js/issues/2907'); + if (glyphQuadEndIndex > SymbolBucket.MAX_QUADS) + util.warnOnce('Too many glyphs being rendered in a tile. See https://github.com/mapbox/mapbox-gl-js/issues/2907'); + return this.symbolInstancesArray.emplaceBack(textBoxStartIndex, textBoxEndIndex, iconBoxStartIndex, iconBoxEndIndex, glyphQuadStartIndex, glyphQuadEndIndex, iconQuadStartIndex, iconQuadEndIndex, anchor.x, anchor.y, index); +}; +SymbolBucket.prototype.addSymbolQuad = function (symbolQuad) { + return this.symbolQuadsArray.emplaceBack(symbolQuad.anchorPoint.x, symbolQuad.anchorPoint.y, symbolQuad.tl.x, symbolQuad.tl.y, symbolQuad.tr.x, symbolQuad.tr.y, symbolQuad.bl.x, symbolQuad.bl.y, symbolQuad.br.x, symbolQuad.br.y, symbolQuad.tex.h, symbolQuad.tex.w, symbolQuad.tex.x, symbolQuad.tex.y, symbolQuad.anchorAngle, symbolQuad.glyphAngle, symbolQuad.maxScale, symbolQuad.minScale); +}; +},{"../../symbol/anchor":135,"../../symbol/clip_line":137,"../../symbol/collision_feature":139,"../../symbol/get_anchors":141,"../../symbol/mergelines":144,"../../symbol/quads":145,"../../symbol/resolve_text":146,"../../symbol/shaping":147,"../../util/classify_rings":174,"../../util/find_pole_of_inaccessibility":180,"../../util/token":187,"../../util/util":188,"../bucket":72,"../load_geometry":80,"point-geometry":196}],77:[function(require,module,exports){ 'use strict'; - -var util = require('../../util/util'); -var StyleLayer = require('../style_layer'); - -function SymbolStyleLayer() { - StyleLayer.apply(this, arguments); -} - -module.exports = SymbolStyleLayer; - -SymbolStyleLayer.prototype = util.inherit(StyleLayer, { - - isHidden: function() { - if (StyleLayer.prototype.isHidden.apply(this, arguments)) return true; - - var isTextHidden = this.paint['text-opacity'] === 0 || !this.layout['text-field']; - var isIconHidden = this.paint['icon-opacity'] === 0 || !this.layout['icon-image']; - if (isTextHidden && isIconHidden) return true; - - return false; - }, - - getLayoutValue: function(name, zoom, zoomHistory) { - if (name === 'text-rotation-alignment' && - this.getLayoutValue('symbol-placement', zoom, zoomHistory) === 'line' && - !this.getLayoutProperty('text-rotation-alignment')) { - return 'map'; - } else if (name === 'icon-rotation-alignment' && - this.getLayoutValue('symbol-placement', zoom, zoomHistory) === 'line' && - !this.getLayoutProperty('icon-rotation-alignment')) { - return 'map'; - } else { - return StyleLayer.prototype.getLayoutValue.apply(this, arguments); +module.exports = Buffer; +function Buffer(array, arrayType, type) { + this.arrayBuffer = array.arrayBuffer; + this.length = array.length; + this.attributes = arrayType.members; + this.itemSize = arrayType.bytesPerElement; + this.type = type; + this.arrayType = arrayType; +} +Buffer.prototype.bind = function (gl) { + var type = gl[this.type]; + if (!this.buffer) { + this.buffer = gl.createBuffer(); + gl.bindBuffer(type, this.buffer); + gl.bufferData(type, this.arrayBuffer, gl.STATIC_DRAW); + this.arrayBuffer = null; + } else { + gl.bindBuffer(type, this.buffer); + } +}; +var AttributeType = { + Int8: 'BYTE', + Uint8: 'UNSIGNED_BYTE', + Int16: 'SHORT', + Uint16: 'UNSIGNED_SHORT' +}; +Buffer.prototype.setVertexAttribPointers = function (gl, program) { + for (var j = 0; j < this.attributes.length; j++) { + var member = this.attributes[j]; + var attribIndex = program[member.name]; + if (attribIndex !== undefined) { + gl.vertexAttribPointer(attribIndex, member.components, gl[AttributeType[member.type]], false, this.arrayType.bytesPerElement, member.offset); } } - -}); - -},{"../../util/util":113,"../style_layer":63}],70:[function(require,module,exports){ +}; +Buffer.prototype.destroy = function (gl) { + if (this.buffer) { + gl.deleteBuffer(this.buffer); + } +}; +Buffer.BufferType = { + VERTEX: 'ARRAY_BUFFER', + ELEMENT: 'ELEMENT_ARRAY_BUFFER' +}; +},{}],78:[function(require,module,exports){ 'use strict'; - var util = require('../util/util'); -var interpolate = require('../util/interpolate'); - -module.exports = StyleTransition; - -/* - * Represents a transition between two declarations - */ -function StyleTransition(declaration, oldTransition, value) { - - this.declaration = declaration; - this.startTime = this.endTime = (new Date()).getTime(); - - var type = declaration.type; - if ((type === 'string' || type === 'array') && declaration.transitionable) { - this.interp = interpZoomTransitioned; - } else { - this.interp = interpolate[type]; +var Buffer = require('./buffer'); +var VertexArrayObject = require('../render/vertex_array_object'); +module.exports = BufferGroup; +function BufferGroup(arrayGroup, arrayTypes) { + this.layoutVertexBuffer = new Buffer(arrayGroup.layoutVertexArray, arrayTypes.layoutVertexArrayType, Buffer.BufferType.VERTEX); + if (arrayGroup.elementArray) { + this.elementBuffer = new Buffer(arrayGroup.elementArray, arrayTypes.elementArrayType, Buffer.BufferType.ELEMENT); + } + var vaos = this.vaos = {}; + var secondVaos; + if (arrayGroup.elementArray2) { + this.elementBuffer2 = new Buffer(arrayGroup.elementArray2, arrayTypes.elementArrayType2, Buffer.BufferType.ELEMENT); + secondVaos = this.secondVaos = {}; + } + this.paintVertexBuffers = util.mapObject(arrayGroup.paintVertexArrays, function (array, name) { + vaos[name] = new VertexArrayObject(); + if (arrayGroup.elementArray2) { + secondVaos[name] = new VertexArrayObject(); + } + return new Buffer(array, arrayTypes.paintVertexArrayTypes[name], Buffer.BufferType.VERTEX); + }); +} +BufferGroup.prototype.destroy = function (gl) { + this.layoutVertexBuffer.destroy(gl); + if (this.elementBuffer) { + this.elementBuffer.destroy(gl); } - - this.oldTransition = oldTransition; - this.duration = value.duration || 0; - this.delay = value.delay || 0; - - if (!this.instant()) { - this.endTime = this.startTime + this.duration + this.delay; - this.ease = util.easeCubicInOut; + if (this.elementBuffer2) { + this.elementBuffer2.destroy(gl); } - - if (oldTransition && oldTransition.endTime <= this.startTime) { - // Old transition is done running, so we can - // delete its reference to its old transition. - - delete oldTransition.oldTransition; + for (var n in this.paintVertexBuffers) { + this.paintVertexBuffers[n].destroy(gl); + } + for (var j in this.vaos) { + this.vaos[j].destroy(gl); + } + for (var k in this.secondVaos) { + this.secondVaos[k].destroy(gl); } -} - -StyleTransition.prototype.instant = function() { - return !this.oldTransition || !this.interp || (this.duration === 0 && this.delay === 0); }; - -/* - * Return the value of the transitioning property at zoom level `z` and optional time `t` - */ -StyleTransition.prototype.at = function(z, zoomHistory, t) { - - var value = this.declaration.calculate(z, zoomHistory, this.duration); - - if (this.instant()) return value; - - t = t || Date.now(); - - if (t < this.endTime) { - var oldValue = this.oldTransition.at(z, zoomHistory, this.startTime); - var eased = this.ease((t - this.startTime - this.delay) / this.duration); - value = this.interp(oldValue, value, eased); - } - - return value; - -}; - -function interpZoomTransitioned(from, to, t) { - return { - from: from.to, - fromScale: from.toScale, - to: to.to, - toScale: to.toScale, - t: t - }; -} - -},{"../util/interpolate":109,"../util/util":113}],71:[function(require,module,exports){ +},{"../render/vertex_array_object":101,"../util/util":188,"./buffer":77}],79:[function(require,module,exports){ 'use strict'; - var Point = require('point-geometry'); - -module.exports = Anchor; - -function Anchor(x, y, angle, segment) { - this.x = x; - this.y = y; - this.angle = angle; - - if (segment !== undefined) { - this.segment = segment; +var loadGeometry = require('./load_geometry'); +var EXTENT = require('./bucket').EXTENT; +var featureFilter = require('feature-filter'); +var StructArrayType = require('../util/struct_array'); +var Grid = require('grid-index'); +var DictionaryCoder = require('../util/dictionary_coder'); +var vt = require('vector-tile'); +var Protobuf = require('pbf'); +var GeoJSONFeature = require('../util/vectortile_to_geojson'); +var arraysIntersect = require('../util/util').arraysIntersect; +var intersection = require('../util/intersection_tests'); +var multiPolygonIntersectsBufferedMultiPoint = intersection.multiPolygonIntersectsBufferedMultiPoint; +var multiPolygonIntersectsMultiPolygon = intersection.multiPolygonIntersectsMultiPolygon; +var multiPolygonIntersectsBufferedMultiLine = intersection.multiPolygonIntersectsBufferedMultiLine; +var FeatureIndexArray = new StructArrayType({ + members: [ + { + type: 'Uint32', + name: 'featureIndex' + }, + { + type: 'Uint16', + name: 'sourceLayerIndex' + }, + { + type: 'Uint16', + name: 'bucketIndex' + } + ] +}); +module.exports = FeatureIndex; +function FeatureIndex(coord, overscaling, collisionTile) { + if (coord.grid) { + var serialized = coord; + var rawTileData = overscaling; + coord = serialized.coord; + overscaling = serialized.overscaling; + this.grid = new Grid(serialized.grid); + this.featureIndexArray = new FeatureIndexArray(serialized.featureIndexArray); + this.rawTileData = rawTileData; + this.bucketLayerIDs = serialized.bucketLayerIDs; + } else { + this.grid = new Grid(EXTENT, 16, 0); + this.featureIndexArray = new FeatureIndexArray(); } + this.coord = coord; + this.overscaling = overscaling; + this.x = coord.x; + this.y = coord.y; + this.z = coord.z - Math.log(overscaling) / Math.LN2; + this.setCollisionTile(collisionTile); } - -Anchor.prototype = Object.create(Point.prototype); - -Anchor.prototype.clone = function() { - return new Anchor(this.x, this.y, this.angle, this.segment); +FeatureIndex.prototype.insert = function (feature, featureIndex, sourceLayerIndex, bucketIndex) { + var key = this.featureIndexArray.length; + this.featureIndexArray.emplaceBack(featureIndex, sourceLayerIndex, bucketIndex); + var geometry = loadGeometry(feature); + for (var r = 0; r < geometry.length; r++) { + var ring = geometry[r]; + var bbox = [ + Infinity, + Infinity, + -Infinity, + -Infinity + ]; + for (var i = 0; i < ring.length; i++) { + var p = ring[i]; + bbox[0] = Math.min(bbox[0], p.x); + bbox[1] = Math.min(bbox[1], p.y); + bbox[2] = Math.max(bbox[2], p.x); + bbox[3] = Math.max(bbox[3], p.y); + } + this.grid.insert(key, bbox[0], bbox[1], bbox[2], bbox[3]); + } +}; +FeatureIndex.prototype.setCollisionTile = function (collisionTile) { + this.collisionTile = collisionTile; +}; +FeatureIndex.prototype.serialize = function () { + var data = { + coord: this.coord, + overscaling: this.overscaling, + grid: this.grid.toArrayBuffer(), + featureIndexArray: this.featureIndexArray.serialize(), + bucketLayerIDs: this.bucketLayerIDs + }; + return { + data: data, + transferables: [ + data.grid, + data.featureIndexArray.arrayBuffer + ] + }; }; - -},{"point-geometry":162}],72:[function(require,module,exports){ -'use strict'; - -module.exports = checkMaxAngle; - -/** - * Labels placed around really sharp angles aren't readable. Check if any - * part of the potential label has a combined angle that is too big. - * - * @param {Array} line - * @param {Anchor} anchor The point on the line around which the label is anchored. - * @param {number} labelLength The length of the label in geometry units. - * @param {number} windowSize The check fails if the combined angles within a part of the line that is `windowSize` long is too big. - * @param {number} maxAngle The maximum combined angle that any window along the label is allowed to have. - * - * @returns {boolean} whether the label should be placed - * @private - */ -function checkMaxAngle(line, anchor, labelLength, windowSize, maxAngle) { - - // horizontal labels always pass - if (anchor.segment === undefined) return true; - - var p = anchor; - var index = anchor.segment + 1; - var anchorDistance = 0; - - // move backwards along the line to the first segment the label appears on - while (anchorDistance > -labelLength / 2) { - index--; - - // there isn't enough room for the label after the beginning of the line - if (index < 0) return false; - - anchorDistance -= line[index].dist(p); - p = line[index]; +function translateDistance(translate) { + return Math.sqrt(translate[0] * translate[0] + translate[1] * translate[1]); +} +FeatureIndex.prototype.query = function (args, styleLayers) { + if (!this.vtLayers) { + this.vtLayers = new vt.VectorTile(new Protobuf(this.rawTileData)).layers; + this.sourceLayerCoder = new DictionaryCoder(this.vtLayers ? Object.keys(this.vtLayers).sort() : ['_geojsonTileLayer']); } - - anchorDistance += line[index].dist(line[index + 1]); - index++; - - // store recent corners and their total angle difference - var recentCorners = []; - var recentAngleDelta = 0; - - // move forwards by the length of the label and check angles along the way - while (anchorDistance < labelLength / 2) { - var prev = line[index - 1]; - var current = line[index]; - var next = line[index + 1]; - - // there isn't enough room for the label before the end of the line - if (!next) return false; - - var angleDelta = prev.angleTo(current) - current.angleTo(next); - // restrict angle to -pi..pi range - angleDelta = Math.abs(((angleDelta + 3 * Math.PI) % (Math.PI * 2)) - Math.PI); - - recentCorners.push({ - distance: anchorDistance, - angleDelta: angleDelta + var result = {}; + var params = args.params || {}, pixelsToTileUnits = EXTENT / args.tileSize / args.scale, filter = featureFilter(params.filter); + var additionalRadius = 0; + for (var id in styleLayers) { + var styleLayer = styleLayers[id]; + var paint = styleLayer.paint; + var styleLayerDistance = 0; + if (styleLayer.type === 'line') { + styleLayerDistance = getLineWidth(paint) / 2 + Math.abs(paint['line-offset']) + translateDistance(paint['line-translate']); + } else if (styleLayer.type === 'fill') { + styleLayerDistance = translateDistance(paint['fill-translate']); + } else if (styleLayer.type === 'circle') { + styleLayerDistance = paint['circle-radius'] + translateDistance(paint['circle-translate']); + } + additionalRadius = Math.max(additionalRadius, styleLayerDistance * pixelsToTileUnits); + } + var queryGeometry = args.queryGeometry.map(function (q) { + return q.map(function (p) { + return new Point(p.x, p.y); }); - recentAngleDelta += angleDelta; - - // remove corners that are far enough away from the list of recent anchors - while (anchorDistance - recentCorners[0].distance > windowSize) { - recentAngleDelta -= recentCorners.shift().angleDelta; - } - - // the sum of angles within the window area exceeds the maximum allowed value. check fails. - if (recentAngleDelta > maxAngle) return false; - - index++; - anchorDistance += current.dist(next); + }); + var minX = Infinity; + var minY = Infinity; + var maxX = -Infinity; + var maxY = -Infinity; + for (var i = 0; i < queryGeometry.length; i++) { + var ring = queryGeometry[i]; + for (var k = 0; k < ring.length; k++) { + var p = ring[k]; + minX = Math.min(minX, p.x); + minY = Math.min(minY, p.y); + maxX = Math.max(maxX, p.x); + maxY = Math.max(maxY, p.y); + } + } + var matching = this.grid.query(minX - additionalRadius, minY - additionalRadius, maxX + additionalRadius, maxY + additionalRadius); + matching.sort(topDownFeatureComparator); + this.filterMatching(result, matching, this.featureIndexArray, queryGeometry, filter, params.layers, styleLayers, args.bearing, pixelsToTileUnits); + var matchingSymbols = this.collisionTile.queryRenderedSymbols(minX, minY, maxX, maxY, args.scale); + matchingSymbols.sort(); + this.filterMatching(result, matchingSymbols, this.collisionTile.collisionBoxArray, queryGeometry, filter, params.layers, styleLayers, args.bearing, pixelsToTileUnits); + return result; +}; +function topDownFeatureComparator(a, b) { + return b - a; +} +function getLineWidth(paint) { + if (paint['line-gap-width'] > 0) { + return paint['line-gap-width'] + 2 * paint['line-width']; + } else { + return paint['line-width']; } - - // no part of the line had an angle greater than the maximum allowed. check passes. - return true; } - -},{}],73:[function(require,module,exports){ -'use strict'; - -var Point = require('point-geometry'); - -module.exports = clipLine; - -/** - * Returns the part of a multiline that intersects with the provided rectangular box. - * - * @param {Array>} lines - * @param {number} x1 the left edge of the box - * @param {number} y1 the top edge of the box - * @param {number} x2 the right edge of the box - * @param {number} y2 the bottom edge of the box - * @returns {Array>} lines - * @private - */ -function clipLine(lines, x1, y1, x2, y2) { - var clippedLines = []; - - for (var l = 0; l < lines.length; l++) { - var line = lines[l]; - var clippedLine; - - for (var i = 0; i < line.length - 1; i++) { - var p0 = line[i]; - var p1 = line[i + 1]; - - - if (p0.x < x1 && p1.x < x1) { - continue; - } else if (p0.x < x1) { - p0 = new Point(x1, p0.y + (p1.y - p0.y) * ((x1 - p0.x) / (p1.x - p0.x))); - } else if (p1.x < x1) { - p1 = new Point(x1, p0.y + (p1.y - p0.y) * ((x1 - p0.x) / (p1.x - p0.x))); - } - - if (p0.y < y1 && p1.y < y1) { - continue; - } else if (p0.y < y1) { - p0 = new Point(p0.x + (p1.x - p0.x) * ((y1 - p0.y) / (p1.y - p0.y)), y1); - } else if (p1.y < y1) { - p1 = new Point(p0.x + (p1.x - p0.x) * ((y1 - p0.y) / (p1.y - p0.y)), y1); - } - - if (p0.x >= x2 && p1.x >= x2) { +FeatureIndex.prototype.filterMatching = function (result, matching, array, queryGeometry, filter, filterLayerIDs, styleLayers, bearing, pixelsToTileUnits) { + var previousIndex; + for (var k = 0; k < matching.length; k++) { + var index = matching[k]; + if (index === previousIndex) + continue; + previousIndex = index; + var match = array.get(index); + var layerIDs = this.bucketLayerIDs[match.bucketIndex]; + if (filterLayerIDs && !arraysIntersect(filterLayerIDs, layerIDs)) + continue; + var sourceLayerName = this.sourceLayerCoder.decode(match.sourceLayerIndex); + var sourceLayer = this.vtLayers[sourceLayerName]; + var feature = sourceLayer.feature(match.featureIndex); + if (!filter(feature)) + continue; + var geometry = null; + for (var l = 0; l < layerIDs.length; l++) { + var layerID = layerIDs[l]; + if (filterLayerIDs && filterLayerIDs.indexOf(layerID) < 0) { continue; - } else if (p0.x >= x2) { - p0 = new Point(x2, p0.y + (p1.y - p0.y) * ((x2 - p0.x) / (p1.x - p0.x))); - } else if (p1.x >= x2) { - p1 = new Point(x2, p0.y + (p1.y - p0.y) * ((x2 - p0.x) / (p1.x - p0.x))); } - - if (p0.y >= y2 && p1.y >= y2) { + var styleLayer = styleLayers[layerID]; + if (!styleLayer) continue; - } else if (p0.y >= y2) { - p0 = new Point(p0.x + (p1.x - p0.x) * ((y2 - p0.y) / (p1.y - p0.y)), y2); - } else if (p1.y >= y2) { - p1 = new Point(p0.x + (p1.x - p0.x) * ((y2 - p0.y) / (p1.y - p0.y)), y2); + var translatedPolygon; + if (styleLayer.type !== 'symbol') { + if (!geometry) + geometry = loadGeometry(feature); + var paint = styleLayer.paint; + if (styleLayer.type === 'line') { + translatedPolygon = translate(queryGeometry, paint['line-translate'], paint['line-translate-anchor'], bearing, pixelsToTileUnits); + var halfWidth = getLineWidth(paint) / 2 * pixelsToTileUnits; + if (paint['line-offset']) { + geometry = offsetLine(geometry, paint['line-offset'] * pixelsToTileUnits); + } + if (!multiPolygonIntersectsBufferedMultiLine(translatedPolygon, geometry, halfWidth)) + continue; + } else if (styleLayer.type === 'fill') { + translatedPolygon = translate(queryGeometry, paint['fill-translate'], paint['fill-translate-anchor'], bearing, pixelsToTileUnits); + if (!multiPolygonIntersectsMultiPolygon(translatedPolygon, geometry)) + continue; + } else if (styleLayer.type === 'circle') { + translatedPolygon = translate(queryGeometry, paint['circle-translate'], paint['circle-translate-anchor'], bearing, pixelsToTileUnits); + var circleRadius = paint['circle-radius'] * pixelsToTileUnits; + if (!multiPolygonIntersectsBufferedMultiPoint(translatedPolygon, geometry, circleRadius)) + continue; + } } - - if (!clippedLine || !p0.equals(clippedLine[clippedLine.length - 1])) { - clippedLine = [p0]; - clippedLines.push(clippedLine); + var geojsonFeature = new GeoJSONFeature(feature, this.z, this.x, this.y); + geojsonFeature.layer = styleLayer.serialize({ includeRefProperties: true }); + var layerResult = result[layerID]; + if (layerResult === undefined) { + layerResult = result[layerID] = []; } - - clippedLine.push(p1); + layerResult.push(geojsonFeature); } } - - return clippedLines; +}; +function translate(queryGeometry, translate, translateAnchor, bearing, pixelsToTileUnits) { + if (!translate[0] && !translate[1]) { + return queryGeometry; + } + translate = Point.convert(translate); + if (translateAnchor === 'viewport') { + translate._rotate(-bearing); + } + var translated = []; + for (var i = 0; i < queryGeometry.length; i++) { + var ring = queryGeometry[i]; + var translatedRing = []; + for (var k = 0; k < ring.length; k++) { + translatedRing.push(ring[k].sub(translate._mult(pixelsToTileUnits))); + } + translated.push(translatedRing); + } + return translated; } - -},{"point-geometry":162}],74:[function(require,module,exports){ +function offsetLine(rings, offset) { + var newRings = []; + var zero = new Point(0, 0); + for (var k = 0; k < rings.length; k++) { + var ring = rings[k]; + var newRing = []; + for (var i = 0; i < ring.length; i++) { + var a = ring[i - 1]; + var b = ring[i]; + var c = ring[i + 1]; + var aToB = i === 0 ? zero : b.sub(a)._unit()._perp(); + var bToC = i === ring.length - 1 ? zero : c.sub(b)._unit()._perp(); + var extrude = aToB._add(bToC)._unit(); + var cosHalfAngle = extrude.x * bToC.x + extrude.y * bToC.y; + extrude._mult(1 / cosHalfAngle); + newRing.push(extrude._mult(offset)._add(b)); + } + newRings.push(newRing); + } + return newRings; +} +},{"../util/dictionary_coder":176,"../util/intersection_tests":183,"../util/struct_array":186,"../util/util":188,"../util/vectortile_to_geojson":189,"./bucket":72,"./load_geometry":80,"feature-filter":12,"grid-index":39,"pbf":192,"point-geometry":196,"vector-tile":212}],80:[function(require,module,exports){ 'use strict'; - -module.exports = CollisionBox; - -/** - * A collision box represents an area of the map that that is covered by a - * label. CollisionFeature uses one or more of these collision boxes to - * represent all the area covered by a single label. They are used to - * prevent collisions between labels. - * - * A collision box actually represents a 3d volume. The first two dimensions, - * x and y, are specified with `anchor` along with `x1`, `y1`, `x2`, `y2`. - * The third dimension, zoom, is limited by `maxScale` which determines - * how far in the z dimensions the box extends. - * - * As you zoom in on a map, all points on the map get further and further apart - * but labels stay roughly the same size. Labels cover less real world area on - * the map at higher zoom levels than they do at lower zoom levels. This is why - * areas are are represented with an anchor point and offsets from that point - * instead of just using four absolute points. - * - * Line labels are represented by a set of these boxes spaced out along a line. - * When you zoom in, line labels cover less real world distance along the line - * than they used to. Collision boxes near the edges that used to cover label - * no longer do. If a box doesn't cover the label anymore it should be ignored - * when doing collision checks. `maxScale` is how much you can scale the map - * before the label isn't within the box anymore. - * For example - * lower zoom: - * https://cloud.githubusercontent.com/assets/1421652/8060094/4d975f76-0e91-11e5-84b1-4edeb30a5875.png - * slightly higher zoom: - * https://cloud.githubusercontent.com/assets/1421652/8060061/26ae1c38-0e91-11e5-8c5a-9f380bf29f0a.png - * In the zoomed in image the two grey boxes on either side don't cover the - * label anymore. Their maxScale is smaller than the current scale. - * - * - * @class CollisionBox - * @param {Point} anchorPoint The anchor point the box is centered around. - * @param {number} x1 The distance from the anchor to the left edge. - * @param {number} y1 The distance from the anchor to the top edge. - * @param {number} x2 The distance from the anchor to the right edge. - * @param {number} y2 The distance from the anchor to the bottom edge. - * @param {number} maxScale The maximum scale this box can block other boxes at. - * @private - */ -function CollisionBox(anchorPoint, x1, y1, x2, y2, maxScale) { - // the box is centered around the anchor point - this.anchorPoint = anchorPoint; - - // distances to the edges from the anchor - this.x1 = x1; - this.y1 = y1; - this.x2 = x2; - this.y2 = y2; - - // the box is only valid for scales < maxScale. - // The box does not block other boxes at scales >= maxScale; - this.maxScale = maxScale; - - // the scale at which the label can first be shown - this.placementScale = 0; - - // rotated and scaled bbox used for indexing - this[0] = this[1] = this[2] = this[3] = 0; +var util = require('../util/util'); +var EXTENT = require('./bucket').EXTENT; +function createBounds(bits) { + return { + min: -1 * Math.pow(2, bits - 1), + max: Math.pow(2, bits - 1) - 1 + }; } - -},{}],75:[function(require,module,exports){ -'use strict'; - -var CollisionBox = require('./collision_box'); -var Point = require('point-geometry'); - -module.exports = CollisionFeature; - -/** - * A CollisionFeature represents the area of the tile covered by a single label. - * It is used with CollisionTile to check if the label overlaps with any - * previous labels. A CollisionFeature is mostly just a set of CollisionBox - * objects. - * - * @class CollisionFeature - * @param {Array} line The geometry the label is placed on. - * @param {Anchor} anchor The point along the line around which the label is anchored. - * @param {Object} shaped The text or icon shaping results. - * @param {number} boxScale A magic number used to convert from glyph metrics units to geometry units. - * @param {number} padding The amount of padding to add around the label edges. - * @param {boolean} alignLine Whether the label is aligned with the line or the viewport. - * - * @private - */ -function CollisionFeature(line, anchor, shaped, boxScale, padding, alignLine, straight) { - - var y1 = shaped.top * boxScale - padding; - var y2 = shaped.bottom * boxScale + padding; - var x1 = shaped.left * boxScale - padding; - var x2 = shaped.right * boxScale + padding; - - this.boxes = []; - - if (alignLine) { - - var height = y2 - y1; - var length = x2 - x1; - - if (height <= 0) return; - - // set minimum box height to avoid very many small labels - height = Math.max(10 * boxScale, height); - - if (straight) { - // used for icon labels that are aligned with the line, but don't curve along it - var vector = line[anchor.segment + 1].sub(line[anchor.segment])._unit()._mult(length); - var straightLine = [anchor.sub(vector), anchor.add(vector)]; - this._addLineCollisionBoxes(straightLine, anchor, 0, length, height); - } else { - // used for text labels that curve along a line - this._addLineCollisionBoxes(line, anchor, anchor.segment, length, height); +var boundsLookup = { + 15: createBounds(15), + 16: createBounds(16) +}; +module.exports = function loadGeometry(feature, bits) { + var bounds = boundsLookup[bits || 16]; + var scale = EXTENT / feature.extent; + var geometry = feature.loadGeometry(); + for (var r = 0; r < geometry.length; r++) { + var ring = geometry[r]; + for (var p = 0; p < ring.length; p++) { + var point = ring[p]; + point.x = Math.round(point.x * scale); + point.y = Math.round(point.y * scale); + if (point.x < bounds.min || point.x > bounds.max || point.y < bounds.min || point.y > bounds.max) { + util.warnOnce('Geometry exceeds allowed extent, reduce your vector tile buffer size'); + } } - - } else { - this.boxes.push(new CollisionBox(new Point(anchor.x, anchor.y), x1, y1, x2, y2, Infinity)); } + return geometry; +}; +},{"../util/util":188,"./bucket":72}],81:[function(require,module,exports){ +'use strict'; +module.exports = Coordinate; +function Coordinate(column, row, zoom) { + this.column = column; + this.row = row; + this.zoom = zoom; } - -/** - * Create a set of CollisionBox objects for a line. - * - * @param {Array} line - * @param {Anchor} anchor - * @param {number} labelLength The length of the label in geometry units. - * @param {number} boxSize The size of the collision boxes that will be created. - * - * @private - */ -CollisionFeature.prototype._addLineCollisionBoxes = function(line, anchor, segment, labelLength, boxSize) { - var step = boxSize / 2; - var nBoxes = Math.floor(labelLength / step); - - // offset the center of the first box by half a box so that the edge of the - // box is at the edge of the label. - var firstBoxOffset = -boxSize / 2; - - var bboxes = this.boxes; - - var p = anchor; - var index = segment + 1; - var anchorDistance = firstBoxOffset; - - // move backwards along the line to the first segment the label appears on - do { - index--; - - // there isn't enough room for the label after the beginning of the line - // checkMaxAngle should have already caught this - if (index < 0) return bboxes; - - anchorDistance -= line[index].dist(p); - p = line[index]; - } while (anchorDistance > -labelLength / 2); - - var segmentLength = line[index].dist(line[index + 1]); - - for (var i = 0; i < nBoxes; i++) { - // the distance the box will be from the anchor - var boxDistanceToAnchor = -labelLength / 2 + i * step; - - // the box is not on the current segment. Move to the next segment. - while (anchorDistance + segmentLength < boxDistanceToAnchor) { - anchorDistance += segmentLength; - index++; - - // There isn't enough room before the end of the line. - if (index + 1 >= line.length) return bboxes; - - segmentLength = line[index].dist(line[index + 1]); - } - - // the distance the box will be from the beginning of the segment - var segmentBoxDistance = boxDistanceToAnchor - anchorDistance; - - var p0 = line[index]; - var p1 = line[index + 1]; - var boxAnchorPoint = p1.sub(p0)._unit()._mult(segmentBoxDistance)._add(p0); - - var distanceToInnerEdge = Math.max(Math.abs(boxDistanceToAnchor - firstBoxOffset) - step / 2, 0); - var maxScale = labelLength / 2 / distanceToInnerEdge; - - bboxes.push(new CollisionBox(boxAnchorPoint, -boxSize / 2, -boxSize / 2, boxSize / 2, boxSize / 2, maxScale)); +Coordinate.prototype = { + clone: function () { + return new Coordinate(this.column, this.row, this.zoom); + }, + zoomTo: function (zoom) { + return this.clone()._zoomTo(zoom); + }, + sub: function (c) { + return this.clone()._sub(c); + }, + _zoomTo: function (zoom) { + var scale = Math.pow(2, zoom - this.zoom); + this.column *= scale; + this.row *= scale; + this.zoom = zoom; + return this; + }, + _sub: function (c) { + c = c.zoomTo(this.zoom); + this.column -= c.column; + this.row -= c.row; + return this; } - - return bboxes; }; - -},{"./collision_box":74,"point-geometry":162}],76:[function(require,module,exports){ +},{}],82:[function(require,module,exports){ 'use strict'; - -var rbush = require('rbush'); -var CollisionBox = require('./collision_box'); -var Point = require('point-geometry'); -var EXTENT = require('../data/buffer').EXTENT; - -module.exports = CollisionTile; - -/** - * A collision tile used to prevent symbols from overlapping. It keep tracks of - * where previous symbols have been placed and is used to check if a new - * symbol overlaps with any previously added symbols. - * - * @class CollisionTile - * @param {number} angle - * @param {number} pitch - * @private - */ -function CollisionTile(angle, pitch) { - this.tree = rbush(); - this.angle = angle; - - var sin = Math.sin(angle), - cos = Math.cos(angle); - this.rotationMatrix = [cos, -sin, sin, cos]; - this.reverseRotationMatrix = [cos, sin, -sin, cos]; - - // Stretch boxes in y direction to account for the map tilt. - this.yStretch = 1 / Math.cos(pitch / 180 * Math.PI); - - // The amount the map is squished depends on the y position. - // Sort of account for this by making all boxes a bit bigger. - this.yStretch = Math.pow(this.yStretch, 1.3); - - this.edges = [ - //left - new CollisionBox(new Point(0, 0), 0, -Infinity, 0, Infinity, Infinity), - // right - new CollisionBox(new Point(EXTENT, 0), 0, -Infinity, 0, Infinity, Infinity), - // top - new CollisionBox(new Point(0, 0), -Infinity, 0, Infinity, 0, Infinity), - // bottom - new CollisionBox(new Point(0, EXTENT), -Infinity, 0, Infinity, 0, Infinity) - ]; -} - -CollisionTile.prototype.minScale = 0.25; -CollisionTile.prototype.maxScale = 2; - - -/** - * Find the scale at which the collisionFeature can be shown without - * overlapping with other features. - * - * @param {CollisionFeature} collisionFeature - * @returns {number} placementScale - * @private - */ -CollisionTile.prototype.placeCollisionFeature = function(collisionFeature, allowOverlap, avoidEdges) { - - var minPlacementScale = this.minScale; - var rotationMatrix = this.rotationMatrix; - var yStretch = this.yStretch; - - for (var b = 0; b < collisionFeature.boxes.length; b++) { - - var box = collisionFeature.boxes[b]; - - if (!allowOverlap) { - var anchorPoint = box.anchorPoint.matMult(rotationMatrix); - var x = anchorPoint.x; - var y = anchorPoint.y; - - box[0] = x + box.x1; - box[1] = y + box.y1 * yStretch; - box[2] = x + box.x2; - box[3] = y + box.y2 * yStretch; - - var blockingBoxes = this.tree.search(box); - - for (var i = 0; i < blockingBoxes.length; i++) { - var blocking = blockingBoxes[i]; - var blockingAnchorPoint = blocking.anchorPoint.matMult(rotationMatrix); - - minPlacementScale = this.getPlacementScale(minPlacementScale, anchorPoint, box, blockingAnchorPoint, blocking); - if (minPlacementScale >= this.maxScale) { - return minPlacementScale; - } - } - } - - if (avoidEdges) { - var reverseRotationMatrix = this.reverseRotationMatrix; - var tl = new Point(box.x1, box.y1).matMult(reverseRotationMatrix); - var tr = new Point(box.x2, box.y1).matMult(reverseRotationMatrix); - var bl = new Point(box.x1, box.y2).matMult(reverseRotationMatrix); - var br = new Point(box.x2, box.y2).matMult(reverseRotationMatrix); - var rotatedCollisionBox = new CollisionBox(box.anchorPoint, - Math.min(tl.x, tr.x, bl.x, br.x), - Math.min(tl.y, tr.x, bl.x, br.x), - Math.max(tl.x, tr.x, bl.x, br.x), - Math.max(tl.y, tr.x, bl.x, br.x), - box.maxScale); - - for (var k = 0; k < this.edges.length; k++) { - var edgeBox = this.edges[k]; - minPlacementScale = this.getPlacementScale(minPlacementScale, box.anchorPoint, rotatedCollisionBox, edgeBox.anchorPoint, edgeBox); - if (minPlacementScale >= this.maxScale) { - return minPlacementScale; - } - } - } - } - - return minPlacementScale; -}; - - -CollisionTile.prototype.getPlacementScale = function(minPlacementScale, anchorPoint, box, blockingAnchorPoint, blocking) { - - // Find the lowest scale at which the two boxes can fit side by side without overlapping. - // Original algorithm: - var s1 = (blocking.x1 - box.x2) / (anchorPoint.x - blockingAnchorPoint.x); // scale at which new box is to the left of old box - var s2 = (blocking.x2 - box.x1) / (anchorPoint.x - blockingAnchorPoint.x); // scale at which new box is to the right of old box - var s3 = (blocking.y1 - box.y2) * this.yStretch / (anchorPoint.y - blockingAnchorPoint.y); // scale at which new box is to the top of old box - var s4 = (blocking.y2 - box.y1) * this.yStretch / (anchorPoint.y - blockingAnchorPoint.y); // scale at which new box is to the bottom of old box - - if (isNaN(s1) || isNaN(s2)) s1 = s2 = 1; - if (isNaN(s3) || isNaN(s4)) s3 = s4 = 1; - - var collisionFreeScale = Math.min(Math.max(s1, s2), Math.max(s3, s4)); - - if (collisionFreeScale > blocking.maxScale) { - // After a box's maxScale the label has shrunk enough that the box is no longer needed to cover it, - // so unblock the new box at the scale that the old box disappears. - collisionFreeScale = blocking.maxScale; - } - - if (collisionFreeScale > box.maxScale) { - // If the box can only be shown after it is visible, then the box can never be shown. - // But the label can be shown after this box is not visible. - collisionFreeScale = box.maxScale; +module.exports = LngLat; +var wrap = require('../util/util').wrap; +function LngLat(lng, lat) { + if (isNaN(lng) || isNaN(lat)) { + throw new Error('Invalid LngLat object: (' + lng + ', ' + lat + ')'); } - - if (collisionFreeScale > minPlacementScale && - collisionFreeScale >= blocking.placementScale) { - // If this collision occurs at a lower scale than previously found collisions - // and the collision occurs while the other label is visible - - // this this is the lowest scale at which the label won't collide with anything - minPlacementScale = collisionFreeScale; + this.lng = +lng; + this.lat = +lat; + if (this.lat > 90 || this.lat < -90) { + throw new Error('Invalid LngLat latitude value: must be between -90 and 90'); } - - return minPlacementScale; +} +LngLat.prototype.wrap = function () { + return new LngLat(wrap(this.lng, -180, 180), this.lat); }; - - -/** - * Remember this collisionFeature and what scale it was placed at to block - * later features from overlapping with it. - * - * @param {CollisionFeature} collisionFeature - * @param {number} minPlacementScale - * @private - */ -CollisionTile.prototype.insertCollisionFeature = function(collisionFeature, minPlacementScale) { - - var boxes = collisionFeature.boxes; - for (var k = 0; k < boxes.length; k++) { - boxes[k].placementScale = minPlacementScale; - } - - if (minPlacementScale < this.maxScale) { - this.tree.load(boxes); +LngLat.prototype.toArray = function () { + return [ + this.lng, + this.lat + ]; +}; +LngLat.prototype.toString = function () { + return 'LngLat(' + this.lng + ', ' + this.lat + ')'; +}; +LngLat.convert = function (input) { + if (input instanceof LngLat) { + return input; + } else if (input && input.hasOwnProperty('lng') && input.hasOwnProperty('lat')) { + return new LngLat(input.lng, input.lat); + } else if (Array.isArray(input) && input.length === 2) { + return new LngLat(input[0], input[1]); + } else { + throw new Error('`LngLatLike` argument must be specified as a LngLat instance, an object {lng: , lat: }, or an array of [, ]'); } }; - -},{"../data/buffer":17,"./collision_box":74,"point-geometry":162,"rbush":163}],77:[function(require,module,exports){ +},{"../util/util":188}],83:[function(require,module,exports){ 'use strict'; - -var interpolate = require('../util/interpolate'); -var Anchor = require('../symbol/anchor'); -var checkMaxAngle = require('./check_max_angle'); - -module.exports = getAnchors; - -function getAnchors(line, spacing, maxAngle, shapedText, shapedIcon, glyphSize, boxScale, overscaling, tileExtent) { - - // Resample a line to get anchor points for labels and check that each - // potential label passes text-max-angle check and has enough froom to fit - // on the line. - - var angleWindowSize = shapedText ? - 3 / 5 * glyphSize * boxScale : - 0; - - var labelLength = Math.max( - shapedText ? shapedText.right - shapedText.left : 0, - shapedIcon ? shapedIcon.right - shapedIcon.left : 0); - - // Is the line continued from outside the tile boundary? - if (line[0].x === 0 || line[0].x === tileExtent || line[0].y === 0 || line[0].y === tileExtent) { - var continuedLine = true; - } - - // Is the label long, relative to the spacing? - // If so, adjust the spacing so there is always a minimum space of `spacing / 4` between label edges. - if (spacing - labelLength * boxScale < spacing / 4) { - spacing = labelLength * boxScale + spacing / 4; +module.exports = LngLatBounds; +var LngLat = require('./lng_lat'); +function LngLatBounds(sw, ne) { + if (!sw) { + return; + } else if (ne) { + this.setSouthWest(sw).setNorthEast(ne); + } else if (sw.length === 4) { + this.setSouthWest([ + sw[0], + sw[1] + ]).setNorthEast([ + sw[2], + sw[3] + ]); + } else { + this.setSouthWest(sw[0]).setNorthEast(sw[1]); } - - // Offset the first anchor by: - // Either half the label length plus a fixed extra offset if the line is not continued - // Or half the spacing if the line is continued. - - // For non-continued lines, add a bit of fixed extra offset to avoid collisions at T intersections. - var fixedExtraOffset = glyphSize * 2; - - var offset = !continuedLine ? - ((labelLength / 2 + fixedExtraOffset) * boxScale * overscaling) % spacing : - (spacing / 2 * overscaling) % spacing; - - return resample(line, offset, spacing, angleWindowSize, maxAngle, labelLength * boxScale, continuedLine, false, tileExtent); } - - -function resample(line, offset, spacing, angleWindowSize, maxAngle, labelLength, continuedLine, placeAtMiddle, tileExtent) { - - var halfLabelLength = labelLength / 2; - var lineLength = 0; - for (var k = 0; k < line.length - 1; k++) { - lineLength += line[k].dist(line[k + 1]); - } - - var distance = 0, - markedDistance = offset - spacing; - - var anchors = []; - - for (var i = 0; i < line.length - 1; i++) { - - var a = line[i], - b = line[i + 1]; - - var segmentDist = a.dist(b), - angle = b.angleTo(a); - - while (markedDistance + spacing < distance + segmentDist) { - markedDistance += spacing; - - var t = (markedDistance - distance) / segmentDist, - x = interpolate(a.x, b.x, t), - y = interpolate(a.y, b.y, t); - - // Check that the point is within the tile boundaries and that - // the label would fit before the beginning and end of the line - // if placed at this point. - if (x >= 0 && x < tileExtent && y >= 0 && y < tileExtent && - markedDistance - halfLabelLength >= 0 && - markedDistance + halfLabelLength <= lineLength) { - x = Math.round(x); - y = Math.round(y); - var anchor = new Anchor(x, y, angle, i); - - if (!angleWindowSize || checkMaxAngle(line, anchor, labelLength, angleWindowSize, maxAngle)) { - anchors.push(anchor); +LngLatBounds.prototype = { + setNorthEast: function (ne) { + this._ne = LngLat.convert(ne); + return this; + }, + setSouthWest: function (sw) { + this._sw = LngLat.convert(sw); + return this; + }, + extend: function (obj) { + var sw = this._sw, ne = this._ne, sw2, ne2; + if (obj instanceof LngLat) { + sw2 = obj; + ne2 = obj; + } else if (obj instanceof LngLatBounds) { + sw2 = obj._sw; + ne2 = obj._ne; + if (!sw2 || !ne2) + return this; + } else { + if (Array.isArray(obj)) { + if (obj.every(Array.isArray)) { + return this.extend(LngLatBounds.convert(obj)); + } else { + return this.extend(LngLat.convert(obj)); } } + return this; } - - distance += segmentDist; - } - - if (!placeAtMiddle && !anchors.length && !continuedLine) { - // The first attempt at finding anchors at which labels can be placed failed. - // Try again, but this time just try placing one anchor at the middle of the line. - // This has the most effect for short lines in overscaled tiles, since the - // initial offset used in overscaled tiles is calculated to align labels with positions in - // parent tiles instead of placing the label as close to the beginning as possible. - anchors = resample(line, distance / 2, spacing, angleWindowSize, maxAngle, labelLength, continuedLine, true, tileExtent); - } - - return anchors; -} - -},{"../symbol/anchor":71,"../util/interpolate":109,"./check_max_angle":72}],78:[function(require,module,exports){ -'use strict'; - -var ShelfPack = require('shelf-pack'); - -module.exports = GlyphAtlas; -function GlyphAtlas(width, height) { - this.width = width; - this.height = height; - - this.bin = new ShelfPack(width, height); - this.index = {}; - this.ids = {}; - this.data = new Uint8Array(width * height); -} - -GlyphAtlas.prototype = { - get debug() { - return 'canvas' in this; - }, - set debug(value) { - if (value && !this.canvas) { - this.canvas = document.createElement('canvas'); - this.canvas.width = this.width; - this.canvas.height = this.height; - document.body.appendChild(this.canvas); - this.ctx = this.canvas.getContext('2d'); - } else if (!value && this.canvas) { - this.canvas.parentNode.removeChild(this.canvas); - delete this.ctx; - delete this.canvas; + if (!sw && !ne) { + this._sw = new LngLat(sw2.lng, sw2.lat); + this._ne = new LngLat(ne2.lng, ne2.lat); + } else { + sw.lng = Math.min(sw2.lng, sw.lng); + sw.lat = Math.min(sw2.lat, sw.lat); + ne.lng = Math.max(ne2.lng, ne.lng); + ne.lat = Math.max(ne2.lat, ne.lat); } + return this; + }, + getCenter: function () { + return new LngLat((this._sw.lng + this._ne.lng) / 2, (this._sw.lat + this._ne.lat) / 2); + }, + getSouthWest: function () { + return this._sw; + }, + getNorthEast: function () { + return this._ne; + }, + getNorthWest: function () { + return new LngLat(this.getWest(), this.getNorth()); + }, + getSouthEast: function () { + return new LngLat(this.getEast(), this.getSouth()); + }, + getWest: function () { + return this._sw.lng; + }, + getSouth: function () { + return this._sw.lat; + }, + getEast: function () { + return this._ne.lng; + }, + getNorth: function () { + return this._ne.lat; + }, + toArray: function () { + return [ + this._sw.toArray(), + this._ne.toArray() + ]; + }, + toString: function () { + return 'LngLatBounds(' + this._sw.toString() + ', ' + this._ne.toString() + ')'; } }; - -GlyphAtlas.prototype.getGlyphs = function() { - var glyphs = {}, - split, - name, - id; - - for (var key in this.ids) { - split = key.split('#'); - name = split[0]; - id = split[1]; - - if (!glyphs[name]) glyphs[name] = []; - glyphs[name].push(id); - } - - return glyphs; -}; - -GlyphAtlas.prototype.getRects = function() { - var rects = {}, - split, - name, - id; - - for (var key in this.ids) { - split = key.split('#'); - name = split[0]; - id = split[1]; - - if (!rects[name]) rects[name] = {}; - rects[name][id] = this.index[key]; - } - - return rects; +LngLatBounds.convert = function (input) { + if (!input || input instanceof LngLatBounds) + return input; + return new LngLatBounds(input); }; - - -GlyphAtlas.prototype.addGlyph = function(id, name, glyph, buffer) { - if (!glyph) { - // console.warn('missing glyph', code, String.fromCharCode(code)); - return null; - } - var key = name + "#" + glyph.id; - - // The glyph is already in this texture. - if (this.index[key]) { - if (this.ids[key].indexOf(id) < 0) { - this.ids[key].push(id); +},{"./lng_lat":82}],84:[function(require,module,exports){ +'use strict'; +var LngLat = require('./lng_lat'), Point = require('point-geometry'), Coordinate = require('./coordinate'), util = require('../util/util'), interp = require('../util/interpolate'), TileCoord = require('../source/tile_coord'), EXTENT = require('../data/bucket').EXTENT, glmatrix = require('gl-matrix'); +var vec4 = glmatrix.vec4, mat4 = glmatrix.mat4, mat2 = glmatrix.mat2; +module.exports = Transform; +function Transform(minZoom, maxZoom) { + this.tileSize = 512; + this._minZoom = minZoom || 0; + this._maxZoom = maxZoom || 22; + this.latRange = [ + -85.05113, + 85.05113 + ]; + this.width = 0; + this.height = 0; + this._center = new LngLat(0, 0); + this.zoom = 0; + this.angle = 0; + this._altitude = 1.5; + this._pitch = 0; + this._unmodified = true; +} +Transform.prototype = { + get minZoom() { + return this._minZoom; + }, + set minZoom(zoom) { + if (this._minZoom === zoom) + return; + this._minZoom = zoom; + this.zoom = Math.max(this.zoom, zoom); + }, + get maxZoom() { + return this._maxZoom; + }, + set maxZoom(zoom) { + if (this._maxZoom === zoom) + return; + this._maxZoom = zoom; + this.zoom = Math.min(this.zoom, zoom); + }, + get worldSize() { + return this.tileSize * this.scale; + }, + get centerPoint() { + return this.size._div(2); + }, + get size() { + return new Point(this.width, this.height); + }, + get bearing() { + return -this.angle / Math.PI * 180; + }, + set bearing(bearing) { + var b = -util.wrap(bearing, -180, 180) * Math.PI / 180; + if (this.angle === b) + return; + this._unmodified = false; + this.angle = b; + this._calcMatrices(); + this.rotationMatrix = mat2.create(); + mat2.rotate(this.rotationMatrix, this.rotationMatrix, this.angle); + }, + get pitch() { + return this._pitch / Math.PI * 180; + }, + set pitch(pitch) { + var p = util.clamp(pitch, 0, 60) / 180 * Math.PI; + if (this._pitch === p) + return; + this._unmodified = false; + this._pitch = p; + this._calcMatrices(); + }, + get altitude() { + return this._altitude; + }, + set altitude(altitude) { + var a = Math.max(0.75, altitude); + if (this._altitude === a) + return; + this._unmodified = false; + this._altitude = a; + this._calcMatrices(); + }, + get zoom() { + return this._zoom; + }, + set zoom(zoom) { + var z = Math.min(Math.max(zoom, this.minZoom), this.maxZoom); + if (this._zoom === z) + return; + this._unmodified = false; + this._zoom = z; + this.scale = this.zoomScale(z); + this.tileZoom = Math.floor(z); + this.zoomFraction = z - this.tileZoom; + this._calcMatrices(); + this._constrain(); + }, + get center() { + return this._center; + }, + set center(center) { + if (center.lat === this._center.lat && center.lng === this._center.lng) + return; + this._unmodified = false; + this._center = center; + this._calcMatrices(); + this._constrain(); + }, + coveringZoomLevel: function (options) { + return (options.roundZoom ? Math.round : Math.floor)(this.zoom + this.scaleZoom(this.tileSize / options.tileSize)); + }, + coveringTiles: function (options) { + var z = this.coveringZoomLevel(options); + var actualZ = z; + if (z < options.minzoom) + return []; + if (z > options.maxzoom) + z = options.maxzoom; + var tr = this, tileCenter = tr.locationCoordinate(tr.center)._zoomTo(z), centerPoint = new Point(tileCenter.column - 0.5, tileCenter.row - 0.5); + return TileCoord.cover(z, [ + tr.pointCoordinate(new Point(0, 0))._zoomTo(z), + tr.pointCoordinate(new Point(tr.width, 0))._zoomTo(z), + tr.pointCoordinate(new Point(tr.width, tr.height))._zoomTo(z), + tr.pointCoordinate(new Point(0, tr.height))._zoomTo(z) + ], options.reparseOverscaled ? actualZ : z).sort(function (a, b) { + return centerPoint.dist(a) - centerPoint.dist(b); + }); + }, + resize: function (width, height) { + this.width = width; + this.height = height; + this.pixelsToGLUnits = [ + 2 / width, + -2 / height + ]; + this._calcMatrices(); + this._constrain(); + }, + get unmodified() { + return this._unmodified; + }, + zoomScale: function (zoom) { + return Math.pow(2, zoom); + }, + scaleZoom: function (scale) { + return Math.log(scale) / Math.LN2; + }, + project: function (lnglat, worldSize) { + return new Point(this.lngX(lnglat.lng, worldSize), this.latY(lnglat.lat, worldSize)); + }, + unproject: function (point, worldSize) { + return new LngLat(this.xLng(point.x, worldSize), this.yLat(point.y, worldSize)); + }, + get x() { + return this.lngX(this.center.lng); + }, + get y() { + return this.latY(this.center.lat); + }, + get point() { + return new Point(this.x, this.y); + }, + lngX: function (lng, worldSize) { + return (180 + lng) * (worldSize || this.worldSize) / 360; + }, + latY: function (lat, worldSize) { + var y = 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360)); + return (180 - y) * (worldSize || this.worldSize) / 360; + }, + xLng: function (x, worldSize) { + return x * 360 / (worldSize || this.worldSize) - 180; + }, + yLat: function (y, worldSize) { + var y2 = 180 - y * 360 / (worldSize || this.worldSize); + return 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90; + }, + panBy: function (offset) { + var point = this.centerPoint._add(offset); + this.center = this.pointLocation(point); + }, + setLocationAtPoint: function (lnglat, point) { + var c = this.locationCoordinate(lnglat); + var coordAtPoint = this.pointCoordinate(point); + var coordCenter = this.pointCoordinate(this.centerPoint); + var translate = coordAtPoint._sub(c); + this._unmodified = false; + this.center = this.coordinateLocation(coordCenter._sub(translate)); + }, + locationPoint: function (lnglat) { + return this.coordinatePoint(this.locationCoordinate(lnglat)); + }, + pointLocation: function (p) { + return this.coordinateLocation(this.pointCoordinate(p)); + }, + locationCoordinate: function (lnglat) { + var k = this.zoomScale(this.tileZoom) / this.worldSize, ll = LngLat.convert(lnglat); + return new Coordinate(this.lngX(ll.lng) * k, this.latY(ll.lat) * k, this.tileZoom); + }, + coordinateLocation: function (coord) { + var worldSize = this.zoomScale(coord.zoom); + return new LngLat(this.xLng(coord.column, worldSize), this.yLat(coord.row, worldSize)); + }, + pointCoordinate: function (p) { + var targetZ = 0; + var coord0 = [ + p.x, + p.y, + 0, + 1 + ]; + var coord1 = [ + p.x, + p.y, + 1, + 1 + ]; + vec4.transformMat4(coord0, coord0, this.pixelMatrixInverse); + vec4.transformMat4(coord1, coord1, this.pixelMatrixInverse); + var w0 = coord0[3]; + var w1 = coord1[3]; + var x0 = coord0[0] / w0; + var x1 = coord1[0] / w1; + var y0 = coord0[1] / w0; + var y1 = coord1[1] / w1; + var z0 = coord0[2] / w0; + var z1 = coord1[2] / w1; + var t = z0 === z1 ? 0 : (targetZ - z0) / (z1 - z0); + var scale = this.worldSize / this.zoomScale(this.tileZoom); + return new Coordinate(interp(x0, x1, t) / scale, interp(y0, y1, t) / scale, this.tileZoom); + }, + coordinatePoint: function (coord) { + var scale = this.worldSize / this.zoomScale(coord.zoom); + var p = [ + coord.column * scale, + coord.row * scale, + 0, + 1 + ]; + vec4.transformMat4(p, p, this.pixelMatrix); + return new Point(p[0] / p[3], p[1] / p[3]); + }, + calculatePosMatrix: function (coord, maxZoom) { + if (maxZoom === undefined) + maxZoom = Infinity; + if (coord instanceof TileCoord) + coord = coord.toCoordinate(maxZoom); + var z = Math.min(coord.zoom, maxZoom); + var scale = this.worldSize / Math.pow(2, z); + var posMatrix = new Float64Array(16); + mat4.identity(posMatrix); + mat4.translate(posMatrix, posMatrix, [ + coord.column * scale, + coord.row * scale, + 0 + ]); + mat4.scale(posMatrix, posMatrix, [ + scale / EXTENT, + scale / EXTENT, + 1 + ]); + mat4.multiply(posMatrix, this.projMatrix, posMatrix); + return new Float32Array(posMatrix); + }, + _constrain: function () { + if (!this.center || !this.width || !this.height || this._constraining) + return; + this._constraining = true; + var minY, maxY, minX, maxX, sy, sx, x2, y2, size = this.size, unmodified = this._unmodified; + if (this.latRange) { + minY = this.latY(this.latRange[1]); + maxY = this.latY(this.latRange[0]); + sy = maxY - minY < size.y ? size.y / (maxY - minY) : 0; } - return this.index[key]; + if (this.lngRange) { + minX = this.lngX(this.lngRange[0]); + maxX = this.lngX(this.lngRange[1]); + sx = maxX - minX < size.x ? size.x / (maxX - minX) : 0; + } + var s = Math.max(sx || 0, sy || 0); + if (s) { + this.center = this.unproject(new Point(sx ? (maxX + minX) / 2 : this.x, sy ? (maxY + minY) / 2 : this.y)); + this.zoom += this.scaleZoom(s); + this._unmodified = unmodified; + this._constraining = false; + return; + } + if (this.latRange) { + var y = this.y, h2 = size.y / 2; + if (y - h2 < minY) + y2 = minY + h2; + if (y + h2 > maxY) + y2 = maxY - h2; + } + if (this.lngRange) { + var x = this.x, w2 = size.x / 2; + if (x - w2 < minX) + x2 = minX + w2; + if (x + w2 > maxX) + x2 = maxX - w2; + } + if (x2 !== undefined || y2 !== undefined) { + this.center = this.unproject(new Point(x2 !== undefined ? x2 : this.x, y2 !== undefined ? y2 : this.y)); + } + this._unmodified = unmodified; + this._constraining = false; + }, + _calcMatrices: function () { + if (!this.height) + return; + var halfFov = Math.atan(0.5 / this.altitude); + var topHalfSurfaceDistance = Math.sin(halfFov) * this.altitude / Math.sin(Math.PI / 2 - this._pitch - halfFov); + var farZ = Math.cos(Math.PI / 2 - this._pitch) * topHalfSurfaceDistance + this.altitude; + var m = new Float64Array(16); + mat4.perspective(m, 2 * Math.atan(this.height / 2 / this.altitude), this.width / this.height, 0.1, farZ); + mat4.translate(m, m, [ + 0, + 0, + -this.altitude + ]); + mat4.scale(m, m, [ + 1, + -1, + 1 / this.height + ]); + mat4.rotateX(m, m, this._pitch); + mat4.rotateZ(m, m, this.angle); + mat4.translate(m, m, [ + -this.x, + -this.y, + 0 + ]); + this.projMatrix = m; + m = mat4.create(); + mat4.scale(m, m, [ + this.width / 2, + -this.height / 2, + 1 + ]); + mat4.translate(m, m, [ + 1, + -1, + 0 + ]); + this.pixelMatrix = mat4.multiply(new Float64Array(16), m, this.projMatrix); + m = mat4.invert(new Float64Array(16), this.pixelMatrix); + if (!m) + throw new Error('failed to invert matrix'); + this.pixelMatrixInverse = m; } - - // The glyph bitmap has zero width. - if (!glyph.bitmap) { - return null; +}; +},{"../data/bucket":72,"../source/tile_coord":113,"../util/interpolate":182,"../util/util":188,"./coordinate":81,"./lng_lat":82,"gl-matrix":29,"point-geometry":196}],85:[function(require,module,exports){ +'use strict'; +var WorkerPool = require('./util/worker_pool'); +var globalWorkerPool; +module.exports = function getGlobalWorkerPool() { + if (!globalWorkerPool) { + globalWorkerPool = new WorkerPool(); } - - var bufferedWidth = glyph.width + buffer * 2; - var bufferedHeight = glyph.height + buffer * 2; - - // Add a 1px border around every image. - var padding = 1; - var packWidth = bufferedWidth + 2 * padding; - var packHeight = bufferedHeight + 2 * padding; - - // Increase to next number divisible by 4, but at least 1. - // This is so we can scale down the texture coordinates and pack them - // into 2 bytes rather than 4 bytes. - packWidth += (4 - packWidth % 4); - packHeight += (4 - packHeight % 4); - - var rect = this.bin.allocate(packWidth, packHeight); - if (rect.x < 0) { - this.resize(); - rect = this.bin.allocate(packWidth, packHeight); - } - if (rect.x < 0) { - console.warn('glyph bitmap overflow'); - return { glyph: glyph, rect: null }; - } - - this.index[key] = rect; - this.ids[key] = [id]; - - var target = this.data; - var source = glyph.bitmap; - for (var y = 0; y < bufferedHeight; y++) { - var y1 = this.width * (rect.y + y + padding) + rect.x + padding; - var y2 = bufferedWidth * y; - for (var x = 0; x < bufferedWidth; x++) { - target[y1 + x] = source[y2 + x]; + return globalWorkerPool; +}; +},{"./util/worker_pool":190}],86:[function(require,module,exports){ +'use strict'; +var simplexFont = { + ' ': [ + 16, + [] + ], + '!': [ + 10, + [ + 5, + 21, + 5, + 7, + -1, + -1, + 5, + 2, + 4, + 1, + 5, + 0, + 6, + 1, + 5, + 2 + ] + ], + '"': [ + 16, + [ + 4, + 21, + 4, + 14, + -1, + -1, + 12, + 21, + 12, + 14 + ] + ], + '#': [ + 21, + [ + 11, + 25, + 4, + -7, + -1, + -1, + 17, + 25, + 10, + -7, + -1, + -1, + 4, + 12, + 18, + 12, + -1, + -1, + 3, + 6, + 17, + 6 + ] + ], + '$': [ + 20, + [ + 8, + 25, + 8, + -4, + -1, + -1, + 12, + 25, + 12, + -4, + -1, + -1, + 17, + 18, + 15, + 20, + 12, + 21, + 8, + 21, + 5, + 20, + 3, + 18, + 3, + 16, + 4, + 14, + 5, + 13, + 7, + 12, + 13, + 10, + 15, + 9, + 16, + 8, + 17, + 6, + 17, + 3, + 15, + 1, + 12, + 0, + 8, + 0, + 5, + 1, + 3, + 3 + ] + ], + '%': [ + 24, + [ + 21, + 21, + 3, + 0, + -1, + -1, + 8, + 21, + 10, + 19, + 10, + 17, + 9, + 15, + 7, + 14, + 5, + 14, + 3, + 16, + 3, + 18, + 4, + 20, + 6, + 21, + 8, + 21, + 10, + 20, + 13, + 19, + 16, + 19, + 19, + 20, + 21, + 21, + -1, + -1, + 17, + 7, + 15, + 6, + 14, + 4, + 14, + 2, + 16, + 0, + 18, + 0, + 20, + 1, + 21, + 3, + 21, + 5, + 19, + 7, + 17, + 7 + ] + ], + '&': [ + 26, + [ + 23, + 12, + 23, + 13, + 22, + 14, + 21, + 14, + 20, + 13, + 19, + 11, + 17, + 6, + 15, + 3, + 13, + 1, + 11, + 0, + 7, + 0, + 5, + 1, + 4, + 2, + 3, + 4, + 3, + 6, + 4, + 8, + 5, + 9, + 12, + 13, + 13, + 14, + 14, + 16, + 14, + 18, + 13, + 20, + 11, + 21, + 9, + 20, + 8, + 18, + 8, + 16, + 9, + 13, + 11, + 10, + 16, + 3, + 18, + 1, + 20, + 0, + 22, + 0, + 23, + 1, + 23, + 2 + ] + ], + '\'': [ + 10, + [ + 5, + 19, + 4, + 20, + 5, + 21, + 6, + 20, + 6, + 18, + 5, + 16, + 4, + 15 + ] + ], + '(': [ + 14, + [ + 11, + 25, + 9, + 23, + 7, + 20, + 5, + 16, + 4, + 11, + 4, + 7, + 5, + 2, + 7, + -2, + 9, + -5, + 11, + -7 + ] + ], + ')': [ + 14, + [ + 3, + 25, + 5, + 23, + 7, + 20, + 9, + 16, + 10, + 11, + 10, + 7, + 9, + 2, + 7, + -2, + 5, + -5, + 3, + -7 + ] + ], + '*': [ + 16, + [ + 8, + 21, + 8, + 9, + -1, + -1, + 3, + 18, + 13, + 12, + -1, + -1, + 13, + 18, + 3, + 12 + ] + ], + '+': [ + 26, + [ + 13, + 18, + 13, + 0, + -1, + -1, + 4, + 9, + 22, + 9 + ] + ], + ',': [ + 10, + [ + 6, + 1, + 5, + 0, + 4, + 1, + 5, + 2, + 6, + 1, + 6, + -1, + 5, + -3, + 4, + -4 + ] + ], + '-': [ + 26, + [ + 4, + 9, + 22, + 9 + ] + ], + '.': [ + 10, + [ + 5, + 2, + 4, + 1, + 5, + 0, + 6, + 1, + 5, + 2 + ] + ], + '/': [ + 22, + [ + 20, + 25, + 2, + -7 + ] + ], + '0': [ + 20, + [ + 9, + 21, + 6, + 20, + 4, + 17, + 3, + 12, + 3, + 9, + 4, + 4, + 6, + 1, + 9, + 0, + 11, + 0, + 14, + 1, + 16, + 4, + 17, + 9, + 17, + 12, + 16, + 17, + 14, + 20, + 11, + 21, + 9, + 21 + ] + ], + '1': [ + 20, + [ + 6, + 17, + 8, + 18, + 11, + 21, + 11, + 0 + ] + ], + '2': [ + 20, + [ + 4, + 16, + 4, + 17, + 5, + 19, + 6, + 20, + 8, + 21, + 12, + 21, + 14, + 20, + 15, + 19, + 16, + 17, + 16, + 15, + 15, + 13, + 13, + 10, + 3, + 0, + 17, + 0 + ] + ], + '3': [ + 20, + [ + 5, + 21, + 16, + 21, + 10, + 13, + 13, + 13, + 15, + 12, + 16, + 11, + 17, + 8, + 17, + 6, + 16, + 3, + 14, + 1, + 11, + 0, + 8, + 0, + 5, + 1, + 4, + 2, + 3, + 4 + ] + ], + '4': [ + 20, + [ + 13, + 21, + 3, + 7, + 18, + 7, + -1, + -1, + 13, + 21, + 13, + 0 + ] + ], + '5': [ + 20, + [ + 15, + 21, + 5, + 21, + 4, + 12, + 5, + 13, + 8, + 14, + 11, + 14, + 14, + 13, + 16, + 11, + 17, + 8, + 17, + 6, + 16, + 3, + 14, + 1, + 11, + 0, + 8, + 0, + 5, + 1, + 4, + 2, + 3, + 4 + ] + ], + '6': [ + 20, + [ + 16, + 18, + 15, + 20, + 12, + 21, + 10, + 21, + 7, + 20, + 5, + 17, + 4, + 12, + 4, + 7, + 5, + 3, + 7, + 1, + 10, + 0, + 11, + 0, + 14, + 1, + 16, + 3, + 17, + 6, + 17, + 7, + 16, + 10, + 14, + 12, + 11, + 13, + 10, + 13, + 7, + 12, + 5, + 10, + 4, + 7 + ] + ], + '7': [ + 20, + [ + 17, + 21, + 7, + 0, + -1, + -1, + 3, + 21, + 17, + 21 + ] + ], + '8': [ + 20, + [ + 8, + 21, + 5, + 20, + 4, + 18, + 4, + 16, + 5, + 14, + 7, + 13, + 11, + 12, + 14, + 11, + 16, + 9, + 17, + 7, + 17, + 4, + 16, + 2, + 15, + 1, + 12, + 0, + 8, + 0, + 5, + 1, + 4, + 2, + 3, + 4, + 3, + 7, + 4, + 9, + 6, + 11, + 9, + 12, + 13, + 13, + 15, + 14, + 16, + 16, + 16, + 18, + 15, + 20, + 12, + 21, + 8, + 21 + ] + ], + '9': [ + 20, + [ + 16, + 14, + 15, + 11, + 13, + 9, + 10, + 8, + 9, + 8, + 6, + 9, + 4, + 11, + 3, + 14, + 3, + 15, + 4, + 18, + 6, + 20, + 9, + 21, + 10, + 21, + 13, + 20, + 15, + 18, + 16, + 14, + 16, + 9, + 15, + 4, + 13, + 1, + 10, + 0, + 8, + 0, + 5, + 1, + 4, + 3 + ] + ], + ':': [ + 10, + [ + 5, + 14, + 4, + 13, + 5, + 12, + 6, + 13, + 5, + 14, + -1, + -1, + 5, + 2, + 4, + 1, + 5, + 0, + 6, + 1, + 5, + 2 + ] + ], + ';': [ + 10, + [ + 5, + 14, + 4, + 13, + 5, + 12, + 6, + 13, + 5, + 14, + -1, + -1, + 6, + 1, + 5, + 0, + 4, + 1, + 5, + 2, + 6, + 1, + 6, + -1, + 5, + -3, + 4, + -4 + ] + ], + '<': [ + 24, + [ + 20, + 18, + 4, + 9, + 20, + 0 + ] + ], + '=': [ + 26, + [ + 4, + 12, + 22, + 12, + -1, + -1, + 4, + 6, + 22, + 6 + ] + ], + '>': [ + 24, + [ + 4, + 18, + 20, + 9, + 4, + 0 + ] + ], + '?': [ + 18, + [ + 3, + 16, + 3, + 17, + 4, + 19, + 5, + 20, + 7, + 21, + 11, + 21, + 13, + 20, + 14, + 19, + 15, + 17, + 15, + 15, + 14, + 13, + 13, + 12, + 9, + 10, + 9, + 7, + -1, + -1, + 9, + 2, + 8, + 1, + 9, + 0, + 10, + 1, + 9, + 2 + ] + ], + '@': [ + 27, + [ + 18, + 13, + 17, + 15, + 15, + 16, + 12, + 16, + 10, + 15, + 9, + 14, + 8, + 11, + 8, + 8, + 9, + 6, + 11, + 5, + 14, + 5, + 16, + 6, + 17, + 8, + -1, + -1, + 12, + 16, + 10, + 14, + 9, + 11, + 9, + 8, + 10, + 6, + 11, + 5, + -1, + -1, + 18, + 16, + 17, + 8, + 17, + 6, + 19, + 5, + 21, + 5, + 23, + 7, + 24, + 10, + 24, + 12, + 23, + 15, + 22, + 17, + 20, + 19, + 18, + 20, + 15, + 21, + 12, + 21, + 9, + 20, + 7, + 19, + 5, + 17, + 4, + 15, + 3, + 12, + 3, + 9, + 4, + 6, + 5, + 4, + 7, + 2, + 9, + 1, + 12, + 0, + 15, + 0, + 18, + 1, + 20, + 2, + 21, + 3, + -1, + -1, + 19, + 16, + 18, + 8, + 18, + 6, + 19, + 5 + ] + ], + 'A': [ + 18, + [ + 9, + 21, + 1, + 0, + -1, + -1, + 9, + 21, + 17, + 0, + -1, + -1, + 4, + 7, + 14, + 7 + ] + ], + 'B': [ + 21, + [ + 4, + 21, + 4, + 0, + -1, + -1, + 4, + 21, + 13, + 21, + 16, + 20, + 17, + 19, + 18, + 17, + 18, + 15, + 17, + 13, + 16, + 12, + 13, + 11, + -1, + -1, + 4, + 11, + 13, + 11, + 16, + 10, + 17, + 9, + 18, + 7, + 18, + 4, + 17, + 2, + 16, + 1, + 13, + 0, + 4, + 0 + ] + ], + 'C': [ + 21, + [ + 18, + 16, + 17, + 18, + 15, + 20, + 13, + 21, + 9, + 21, + 7, + 20, + 5, + 18, + 4, + 16, + 3, + 13, + 3, + 8, + 4, + 5, + 5, + 3, + 7, + 1, + 9, + 0, + 13, + 0, + 15, + 1, + 17, + 3, + 18, + 5 + ] + ], + 'D': [ + 21, + [ + 4, + 21, + 4, + 0, + -1, + -1, + 4, + 21, + 11, + 21, + 14, + 20, + 16, + 18, + 17, + 16, + 18, + 13, + 18, + 8, + 17, + 5, + 16, + 3, + 14, + 1, + 11, + 0, + 4, + 0 + ] + ], + 'E': [ + 19, + [ + 4, + 21, + 4, + 0, + -1, + -1, + 4, + 21, + 17, + 21, + -1, + -1, + 4, + 11, + 12, + 11, + -1, + -1, + 4, + 0, + 17, + 0 + ] + ], + 'F': [ + 18, + [ + 4, + 21, + 4, + 0, + -1, + -1, + 4, + 21, + 17, + 21, + -1, + -1, + 4, + 11, + 12, + 11 + ] + ], + 'G': [ + 21, + [ + 18, + 16, + 17, + 18, + 15, + 20, + 13, + 21, + 9, + 21, + 7, + 20, + 5, + 18, + 4, + 16, + 3, + 13, + 3, + 8, + 4, + 5, + 5, + 3, + 7, + 1, + 9, + 0, + 13, + 0, + 15, + 1, + 17, + 3, + 18, + 5, + 18, + 8, + -1, + -1, + 13, + 8, + 18, + 8 + ] + ], + 'H': [ + 22, + [ + 4, + 21, + 4, + 0, + -1, + -1, + 18, + 21, + 18, + 0, + -1, + -1, + 4, + 11, + 18, + 11 + ] + ], + 'I': [ + 8, + [ + 4, + 21, + 4, + 0 + ] + ], + 'J': [ + 16, + [ + 12, + 21, + 12, + 5, + 11, + 2, + 10, + 1, + 8, + 0, + 6, + 0, + 4, + 1, + 3, + 2, + 2, + 5, + 2, + 7 + ] + ], + 'K': [ + 21, + [ + 4, + 21, + 4, + 0, + -1, + -1, + 18, + 21, + 4, + 7, + -1, + -1, + 9, + 12, + 18, + 0 + ] + ], + 'L': [ + 17, + [ + 4, + 21, + 4, + 0, + -1, + -1, + 4, + 0, + 16, + 0 + ] + ], + 'M': [ + 24, + [ + 4, + 21, + 4, + 0, + -1, + -1, + 4, + 21, + 12, + 0, + -1, + -1, + 20, + 21, + 12, + 0, + -1, + -1, + 20, + 21, + 20, + 0 + ] + ], + 'N': [ + 22, + [ + 4, + 21, + 4, + 0, + -1, + -1, + 4, + 21, + 18, + 0, + -1, + -1, + 18, + 21, + 18, + 0 + ] + ], + 'O': [ + 22, + [ + 9, + 21, + 7, + 20, + 5, + 18, + 4, + 16, + 3, + 13, + 3, + 8, + 4, + 5, + 5, + 3, + 7, + 1, + 9, + 0, + 13, + 0, + 15, + 1, + 17, + 3, + 18, + 5, + 19, + 8, + 19, + 13, + 18, + 16, + 17, + 18, + 15, + 20, + 13, + 21, + 9, + 21 + ] + ], + 'P': [ + 21, + [ + 4, + 21, + 4, + 0, + -1, + -1, + 4, + 21, + 13, + 21, + 16, + 20, + 17, + 19, + 18, + 17, + 18, + 14, + 17, + 12, + 16, + 11, + 13, + 10, + 4, + 10 + ] + ], + 'Q': [ + 22, + [ + 9, + 21, + 7, + 20, + 5, + 18, + 4, + 16, + 3, + 13, + 3, + 8, + 4, + 5, + 5, + 3, + 7, + 1, + 9, + 0, + 13, + 0, + 15, + 1, + 17, + 3, + 18, + 5, + 19, + 8, + 19, + 13, + 18, + 16, + 17, + 18, + 15, + 20, + 13, + 21, + 9, + 21, + -1, + -1, + 12, + 4, + 18, + -2 + ] + ], + 'R': [ + 21, + [ + 4, + 21, + 4, + 0, + -1, + -1, + 4, + 21, + 13, + 21, + 16, + 20, + 17, + 19, + 18, + 17, + 18, + 15, + 17, + 13, + 16, + 12, + 13, + 11, + 4, + 11, + -1, + -1, + 11, + 11, + 18, + 0 + ] + ], + 'S': [ + 20, + [ + 17, + 18, + 15, + 20, + 12, + 21, + 8, + 21, + 5, + 20, + 3, + 18, + 3, + 16, + 4, + 14, + 5, + 13, + 7, + 12, + 13, + 10, + 15, + 9, + 16, + 8, + 17, + 6, + 17, + 3, + 15, + 1, + 12, + 0, + 8, + 0, + 5, + 1, + 3, + 3 + ] + ], + 'T': [ + 16, + [ + 8, + 21, + 8, + 0, + -1, + -1, + 1, + 21, + 15, + 21 + ] + ], + 'U': [ + 22, + [ + 4, + 21, + 4, + 6, + 5, + 3, + 7, + 1, + 10, + 0, + 12, + 0, + 15, + 1, + 17, + 3, + 18, + 6, + 18, + 21 + ] + ], + 'V': [ + 18, + [ + 1, + 21, + 9, + 0, + -1, + -1, + 17, + 21, + 9, + 0 + ] + ], + 'W': [ + 24, + [ + 2, + 21, + 7, + 0, + -1, + -1, + 12, + 21, + 7, + 0, + -1, + -1, + 12, + 21, + 17, + 0, + -1, + -1, + 22, + 21, + 17, + 0 + ] + ], + 'X': [ + 20, + [ + 3, + 21, + 17, + 0, + -1, + -1, + 17, + 21, + 3, + 0 + ] + ], + 'Y': [ + 18, + [ + 1, + 21, + 9, + 11, + 9, + 0, + -1, + -1, + 17, + 21, + 9, + 11 + ] + ], + 'Z': [ + 20, + [ + 17, + 21, + 3, + 0, + -1, + -1, + 3, + 21, + 17, + 21, + -1, + -1, + 3, + 0, + 17, + 0 + ] + ], + '[': [ + 14, + [ + 4, + 25, + 4, + -7, + -1, + -1, + 5, + 25, + 5, + -7, + -1, + -1, + 4, + 25, + 11, + 25, + -1, + -1, + 4, + -7, + 11, + -7 + ] + ], + '\\': [ + 14, + [ + 0, + 21, + 14, + -3 + ] + ], + ']': [ + 14, + [ + 9, + 25, + 9, + -7, + -1, + -1, + 10, + 25, + 10, + -7, + -1, + -1, + 3, + 25, + 10, + 25, + -1, + -1, + 3, + -7, + 10, + -7 + ] + ], + '^': [ + 16, + [ + 6, + 15, + 8, + 18, + 10, + 15, + -1, + -1, + 3, + 12, + 8, + 17, + 13, + 12, + -1, + -1, + 8, + 17, + 8, + 0 + ] + ], + '_': [ + 16, + [ + 0, + -2, + 16, + -2 + ] + ], + '`': [ + 10, + [ + 6, + 21, + 5, + 20, + 4, + 18, + 4, + 16, + 5, + 15, + 6, + 16, + 5, + 17 + ] + ], + 'a': [ + 19, + [ + 15, + 14, + 15, + 0, + -1, + -1, + 15, + 11, + 13, + 13, + 11, + 14, + 8, + 14, + 6, + 13, + 4, + 11, + 3, + 8, + 3, + 6, + 4, + 3, + 6, + 1, + 8, + 0, + 11, + 0, + 13, + 1, + 15, + 3 + ] + ], + 'b': [ + 19, + [ + 4, + 21, + 4, + 0, + -1, + -1, + 4, + 11, + 6, + 13, + 8, + 14, + 11, + 14, + 13, + 13, + 15, + 11, + 16, + 8, + 16, + 6, + 15, + 3, + 13, + 1, + 11, + 0, + 8, + 0, + 6, + 1, + 4, + 3 + ] + ], + 'c': [ + 18, + [ + 15, + 11, + 13, + 13, + 11, + 14, + 8, + 14, + 6, + 13, + 4, + 11, + 3, + 8, + 3, + 6, + 4, + 3, + 6, + 1, + 8, + 0, + 11, + 0, + 13, + 1, + 15, + 3 + ] + ], + 'd': [ + 19, + [ + 15, + 21, + 15, + 0, + -1, + -1, + 15, + 11, + 13, + 13, + 11, + 14, + 8, + 14, + 6, + 13, + 4, + 11, + 3, + 8, + 3, + 6, + 4, + 3, + 6, + 1, + 8, + 0, + 11, + 0, + 13, + 1, + 15, + 3 + ] + ], + 'e': [ + 18, + [ + 3, + 8, + 15, + 8, + 15, + 10, + 14, + 12, + 13, + 13, + 11, + 14, + 8, + 14, + 6, + 13, + 4, + 11, + 3, + 8, + 3, + 6, + 4, + 3, + 6, + 1, + 8, + 0, + 11, + 0, + 13, + 1, + 15, + 3 + ] + ], + 'f': [ + 12, + [ + 10, + 21, + 8, + 21, + 6, + 20, + 5, + 17, + 5, + 0, + -1, + -1, + 2, + 14, + 9, + 14 + ] + ], + 'g': [ + 19, + [ + 15, + 14, + 15, + -2, + 14, + -5, + 13, + -6, + 11, + -7, + 8, + -7, + 6, + -6, + -1, + -1, + 15, + 11, + 13, + 13, + 11, + 14, + 8, + 14, + 6, + 13, + 4, + 11, + 3, + 8, + 3, + 6, + 4, + 3, + 6, + 1, + 8, + 0, + 11, + 0, + 13, + 1, + 15, + 3 + ] + ], + 'h': [ + 19, + [ + 4, + 21, + 4, + 0, + -1, + -1, + 4, + 10, + 7, + 13, + 9, + 14, + 12, + 14, + 14, + 13, + 15, + 10, + 15, + 0 + ] + ], + 'i': [ + 8, + [ + 3, + 21, + 4, + 20, + 5, + 21, + 4, + 22, + 3, + 21, + -1, + -1, + 4, + 14, + 4, + 0 + ] + ], + 'j': [ + 10, + [ + 5, + 21, + 6, + 20, + 7, + 21, + 6, + 22, + 5, + 21, + -1, + -1, + 6, + 14, + 6, + -3, + 5, + -6, + 3, + -7, + 1, + -7 + ] + ], + 'k': [ + 17, + [ + 4, + 21, + 4, + 0, + -1, + -1, + 14, + 14, + 4, + 4, + -1, + -1, + 8, + 8, + 15, + 0 + ] + ], + 'l': [ + 8, + [ + 4, + 21, + 4, + 0 + ] + ], + 'm': [ + 30, + [ + 4, + 14, + 4, + 0, + -1, + -1, + 4, + 10, + 7, + 13, + 9, + 14, + 12, + 14, + 14, + 13, + 15, + 10, + 15, + 0, + -1, + -1, + 15, + 10, + 18, + 13, + 20, + 14, + 23, + 14, + 25, + 13, + 26, + 10, + 26, + 0 + ] + ], + 'n': [ + 19, + [ + 4, + 14, + 4, + 0, + -1, + -1, + 4, + 10, + 7, + 13, + 9, + 14, + 12, + 14, + 14, + 13, + 15, + 10, + 15, + 0 + ] + ], + 'o': [ + 19, + [ + 8, + 14, + 6, + 13, + 4, + 11, + 3, + 8, + 3, + 6, + 4, + 3, + 6, + 1, + 8, + 0, + 11, + 0, + 13, + 1, + 15, + 3, + 16, + 6, + 16, + 8, + 15, + 11, + 13, + 13, + 11, + 14, + 8, + 14 + ] + ], + 'p': [ + 19, + [ + 4, + 14, + 4, + -7, + -1, + -1, + 4, + 11, + 6, + 13, + 8, + 14, + 11, + 14, + 13, + 13, + 15, + 11, + 16, + 8, + 16, + 6, + 15, + 3, + 13, + 1, + 11, + 0, + 8, + 0, + 6, + 1, + 4, + 3 + ] + ], + 'q': [ + 19, + [ + 15, + 14, + 15, + -7, + -1, + -1, + 15, + 11, + 13, + 13, + 11, + 14, + 8, + 14, + 6, + 13, + 4, + 11, + 3, + 8, + 3, + 6, + 4, + 3, + 6, + 1, + 8, + 0, + 11, + 0, + 13, + 1, + 15, + 3 + ] + ], + 'r': [ + 13, + [ + 4, + 14, + 4, + 0, + -1, + -1, + 4, + 8, + 5, + 11, + 7, + 13, + 9, + 14, + 12, + 14 + ] + ], + 's': [ + 17, + [ + 14, + 11, + 13, + 13, + 10, + 14, + 7, + 14, + 4, + 13, + 3, + 11, + 4, + 9, + 6, + 8, + 11, + 7, + 13, + 6, + 14, + 4, + 14, + 3, + 13, + 1, + 10, + 0, + 7, + 0, + 4, + 1, + 3, + 3 + ] + ], + 't': [ + 12, + [ + 5, + 21, + 5, + 4, + 6, + 1, + 8, + 0, + 10, + 0, + -1, + -1, + 2, + 14, + 9, + 14 + ] + ], + 'u': [ + 19, + [ + 4, + 14, + 4, + 4, + 5, + 1, + 7, + 0, + 10, + 0, + 12, + 1, + 15, + 4, + -1, + -1, + 15, + 14, + 15, + 0 + ] + ], + 'v': [ + 16, + [ + 2, + 14, + 8, + 0, + -1, + -1, + 14, + 14, + 8, + 0 + ] + ], + 'w': [ + 22, + [ + 3, + 14, + 7, + 0, + -1, + -1, + 11, + 14, + 7, + 0, + -1, + -1, + 11, + 14, + 15, + 0, + -1, + -1, + 19, + 14, + 15, + 0 + ] + ], + 'x': [ + 17, + [ + 3, + 14, + 14, + 0, + -1, + -1, + 14, + 14, + 3, + 0 + ] + ], + 'y': [ + 16, + [ + 2, + 14, + 8, + 0, + -1, + -1, + 14, + 14, + 8, + 0, + 6, + -4, + 4, + -6, + 2, + -7, + 1, + -7 + ] + ], + 'z': [ + 17, + [ + 14, + 14, + 3, + 0, + -1, + -1, + 3, + 14, + 14, + 14, + -1, + -1, + 3, + 0, + 14, + 0 + ] + ], + '{': [ + 14, + [ + 9, + 25, + 7, + 24, + 6, + 23, + 5, + 21, + 5, + 19, + 6, + 17, + 7, + 16, + 8, + 14, + 8, + 12, + 6, + 10, + -1, + -1, + 7, + 24, + 6, + 22, + 6, + 20, + 7, + 18, + 8, + 17, + 9, + 15, + 9, + 13, + 8, + 11, + 4, + 9, + 8, + 7, + 9, + 5, + 9, + 3, + 8, + 1, + 7, + 0, + 6, + -2, + 6, + -4, + 7, + -6, + -1, + -1, + 6, + 8, + 8, + 6, + 8, + 4, + 7, + 2, + 6, + 1, + 5, + -1, + 5, + -3, + 6, + -5, + 7, + -6, + 9, + -7 + ] + ], + '|': [ + 8, + [ + 4, + 25, + 4, + -7 + ] + ], + '}': [ + 14, + [ + 5, + 25, + 7, + 24, + 8, + 23, + 9, + 21, + 9, + 19, + 8, + 17, + 7, + 16, + 6, + 14, + 6, + 12, + 8, + 10, + -1, + -1, + 7, + 24, + 8, + 22, + 8, + 20, + 7, + 18, + 6, + 17, + 5, + 15, + 5, + 13, + 6, + 11, + 10, + 9, + 6, + 7, + 5, + 5, + 5, + 3, + 6, + 1, + 7, + 0, + 8, + -2, + 8, + -4, + 7, + -6, + -1, + -1, + 8, + 8, + 6, + 6, + 6, + 4, + 7, + 2, + 8, + 1, + 9, + -1, + 9, + -3, + 8, + -5, + 7, + -6, + 5, + -7 + ] + ], + '~': [ + 24, + [ + 3, + 6, + 3, + 8, + 4, + 11, + 6, + 12, + 8, + 12, + 10, + 11, + 14, + 8, + 16, + 7, + 18, + 7, + 20, + 8, + 21, + 10, + -1, + -1, + 3, + 8, + 4, + 10, + 6, + 11, + 8, + 11, + 10, + 10, + 14, + 7, + 16, + 6, + 18, + 6, + 20, + 7, + 21, + 10, + 21, + 12 + ] + ] +}; +module.exports = function textVertices(text, left, baseline, scale) { + scale = scale || 1; + var strokes = [], i, len, j, len2, glyph, x, y, prev; + for (i = 0, len = text.length; i < len; i++) { + glyph = simplexFont[text[i]]; + if (!glyph) + continue; + prev = null; + for (j = 0, len2 = glyph[1].length; j < len2; j += 2) { + if (glyph[1][j] === -1 && glyph[1][j + 1] === -1) { + prev = null; + } else { + x = left + glyph[1][j] * scale; + y = baseline - glyph[1][j + 1] * scale; + if (prev) { + strokes.push(prev.x, prev.y, x, y); + } + prev = { + x: x, + y: y + }; + } } + left += glyph[0] * scale; } - - this.dirty = true; - - return rect; + return strokes; }; - -GlyphAtlas.prototype.resize = function() { - var origw = this.width, - origh = this.height; - - // For now, don't grow the atlas beyond 1024x1024 because of how - // texture coords pack into unsigned byte in symbol bucket. - if (origw > 512 || origh > 512) return; - - if (this.texture) { - if (this.gl) { - this.gl.deleteTexture(this.texture); - } - this.texture = null; +},{}],87:[function(require,module,exports){ +'use strict'; +var browser = require('./util/browser'); +var mapboxgl = module.exports = {}; +mapboxgl.version = require('../package.json').version; +mapboxgl.workerCount = Math.max(browser.hardwareConcurrency - 1, 1); +mapboxgl.Map = require('./ui/map'); +mapboxgl.Control = require('./ui/control/control'); +mapboxgl.Navigation = require('./ui/control/navigation'); +mapboxgl.Geolocate = require('./ui/control/geolocate'); +mapboxgl.Attribution = require('./ui/control/attribution'); +mapboxgl.Scale = require('./ui/control/scale'); +mapboxgl.Popup = require('./ui/popup'); +mapboxgl.Marker = require('./ui/marker'); +mapboxgl.Style = require('./style/style'); +mapboxgl.LngLat = require('./geo/lng_lat'); +mapboxgl.LngLatBounds = require('./geo/lng_lat_bounds'); +mapboxgl.Point = require('point-geometry'); +mapboxgl.Evented = require('./util/evented'); +mapboxgl.util = require('./util/util'); +mapboxgl.supported = require('./util/browser').supported; +var ajax = require('./util/ajax'); +mapboxgl.util.getJSON = ajax.getJSON; +mapboxgl.util.getArrayBuffer = ajax.getArrayBuffer; +var config = require('./util/config'); +mapboxgl.config = config; +Object.defineProperty(mapboxgl, 'accessToken', { + get: function () { + return config.ACCESS_TOKEN; + }, + set: function (token) { + config.ACCESS_TOKEN = token; } - - this.width *= 2; - this.height *= 2; - this.bin.resize(this.width, this.height); - - var buf = new ArrayBuffer(this.width * this.height), - src, dst; - for (var i = 0; i < origh; i++) { - src = new Uint8Array(this.data.buffer, origh * i, origw); - dst = new Uint8Array(buf, origh * i * 2, origw); - dst.set(src); +}); +},{"../package.json":193,"./geo/lng_lat":82,"./geo/lng_lat_bounds":83,"./style/style":122,"./ui/control/attribution":153,"./ui/control/control":154,"./ui/control/geolocate":155,"./ui/control/navigation":156,"./ui/control/scale":157,"./ui/map":166,"./ui/marker":167,"./ui/popup":168,"./util/ajax":170,"./util/browser":171,"./util/config":175,"./util/evented":179,"./util/util":188,"point-geometry":196}],88:[function(require,module,exports){ +'use strict'; +module.exports = function (uniforms) { + var pragmas = { + define: {}, + initialize: {} + }; + for (var i = 0; i < uniforms.length; i++) { + var uniform = uniforms[i]; + var type = '{precision} ' + (uniform.components === 1 ? 'float' : 'vec' + uniform.components); + pragmas.define[uniform.name.slice(2)] = 'uniform ' + type + ' ' + uniform.name + ';\n'; + pragmas.initialize[uniform.name.slice(2)] = type + ' ' + uniform.name.slice(2) + ' = ' + uniform.name + ';\n'; } - this.data = new Uint8Array(buf); + return pragmas; }; - -GlyphAtlas.prototype.bind = function(gl) { - this.gl = gl; - if (!this.texture) { - this.texture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.ALPHA, this.width, this.height, 0, gl.ALPHA, gl.UNSIGNED_BYTE, null); - +},{}],89:[function(require,module,exports){ +'use strict'; +var pixelsToTileUnits = require('../source/pixels_to_tile_units'); +var createUniformPragmas = require('./create_uniform_pragmas'); +var tileSize = 512; +module.exports = drawBackground; +function drawBackground(painter, sourceCache, layer) { + var gl = painter.gl; + var transform = painter.transform; + var color = layer.paint['background-color']; + var image = layer.paint['background-pattern']; + var opacity = layer.paint['background-opacity']; + var program; + var imagePosA = image ? painter.spriteAtlas.getPosition(image.from, true) : null; + var imagePosB = image ? painter.spriteAtlas.getPosition(image.to, true) : null; + painter.setDepthSublayer(0); + if (imagePosA && imagePosB) { + if (painter.isOpaquePass) + return; + program = painter.useProgram('pattern'); + gl.uniform1i(program.u_image, 0); + gl.uniform2fv(program.u_pattern_tl_a, imagePosA.tl); + gl.uniform2fv(program.u_pattern_br_a, imagePosA.br); + gl.uniform2fv(program.u_pattern_tl_b, imagePosB.tl); + gl.uniform2fv(program.u_pattern_br_b, imagePosB.br); + gl.uniform1f(program.u_opacity, opacity); + gl.uniform1f(program.u_mix, image.t); + gl.uniform2fv(program.u_pattern_size_a, imagePosA.size); + gl.uniform2fv(program.u_pattern_size_b, imagePosB.size); + gl.uniform1f(program.u_scale_a, image.fromScale); + gl.uniform1f(program.u_scale_b, image.toScale); + gl.activeTexture(gl.TEXTURE0); + painter.spriteAtlas.bind(gl, true); + painter.tileExtentPatternVAO.bind(gl, program, painter.tileExtentBuffer); } else { - gl.bindTexture(gl.TEXTURE_2D, this.texture); - } -}; - -GlyphAtlas.prototype.updateTexture = function(gl) { - this.bind(gl); - if (this.dirty) { - - gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, this.width, this.height, gl.ALPHA, gl.UNSIGNED_BYTE, this.data); - - // DEBUG - if (this.ctx) { - var data = this.ctx.getImageData(0, 0, this.width, this.height); - for (var i = 0, j = 0; i < this.data.length; i++, j += 4) { - data.data[j] = this.data[i]; - data.data[j + 1] = this.data[i]; - data.data[j + 2] = this.data[i]; - data.data[j + 3] = 255; - } - this.ctx.putImageData(data, 0, 0); - - this.ctx.strokeStyle = 'red'; - for (var k = 0; k < this.bin.free.length; k++) { - var free = this.bin.free[k]; - this.ctx.strokeRect(free.x, free.y, free.w, free.h); + if (painter.isOpaquePass !== (color[3] === 1)) + return; + var pragmas = createUniformPragmas([ + { + name: 'u_color', + components: 4 + }, + { + name: 'u_opacity', + components: 1 } + ]); + program = painter.useProgram('fill', [], pragmas, pragmas); + gl.uniform4fv(program.u_color, color); + gl.uniform1f(program.u_opacity, opacity); + painter.tileExtentVAO.bind(gl, program, painter.tileExtentBuffer); + } + gl.disable(gl.STENCIL_TEST); + var coords = transform.coveringTiles({ tileSize: tileSize }); + for (var c = 0; c < coords.length; c++) { + var coord = coords[c]; + if (imagePosA && imagePosB) { + var tile = { + coord: coord, + tileSize: tileSize + }; + gl.uniform1f(program.u_tile_units_to_pixels, 1 / pixelsToTileUnits(tile, 1, painter.transform.tileZoom)); + var tileSizeAtNearestZoom = tile.tileSize * Math.pow(2, painter.transform.tileZoom - tile.coord.z); + var pixelX = tileSizeAtNearestZoom * (tile.coord.x + coord.w * Math.pow(2, tile.coord.z)); + var pixelY = tileSizeAtNearestZoom * tile.coord.y; + gl.uniform2f(program.u_pixel_coord_upper, pixelX >> 16, pixelY >> 16); + gl.uniform2f(program.u_pixel_coord_lower, pixelX & 65535, pixelY & 65535); } - // END DEBUG - - this.dirty = false; + gl.uniformMatrix4fv(program.u_matrix, false, painter.transform.calculatePosMatrix(coord)); + gl.drawArrays(gl.TRIANGLE_STRIP, 0, painter.tileExtentBuffer.length); } -}; - -},{"shelf-pack":165}],79:[function(require,module,exports){ -'use strict'; - -var normalizeURL = require('../util/mapbox').normalizeGlyphsURL; -var getArrayBuffer = require('../util/ajax').getArrayBuffer; -var Glyphs = require('../util/glyphs'); -var GlyphAtlas = require('../symbol/glyph_atlas'); -var Protobuf = require('pbf'); - -module.exports = GlyphSource; - -/** - * A glyph source has a URL from which to load new glyphs and manages - * GlyphAtlases in which to store glyphs used by the requested fontstacks - * and ranges. - * - * @param {string} url glyph template url - * @private - */ -function GlyphSource(url) { - this.url = url && normalizeURL(url); - this.atlases = {}; - this.stacks = {}; - this.loading = {}; + gl.stencilMask(0); + gl.stencilFunc(gl.EQUAL, 128, 128); } - -GlyphSource.prototype.getSimpleGlyphs = function(fontstack, glyphIDs, uid, callback) { - if (this.stacks[fontstack] === undefined) { - this.stacks[fontstack] = {}; - } - if (this.atlases[fontstack] === undefined) { - this.atlases[fontstack] = new GlyphAtlas(128, 128); +},{"../source/pixels_to_tile_units":107,"./create_uniform_pragmas":88}],90:[function(require,module,exports){ +'use strict'; +var browser = require('../util/browser'); +module.exports = drawCircles; +function drawCircles(painter, sourceCache, layer, coords) { + if (painter.isOpaquePass) + return; + var gl = painter.gl; + painter.setDepthSublayer(0); + painter.depthMask(false); + gl.disable(gl.STENCIL_TEST); + for (var i = 0; i < coords.length; i++) { + var coord = coords[i]; + var tile = sourceCache.getTile(coord); + var bucket = tile.getBucket(layer); + if (!bucket) + continue; + var bufferGroups = bucket.bufferGroups.circle; + if (!bufferGroups) + continue; + var programOptions = bucket.paintAttributes.circle[layer.id]; + var program = painter.useProgram('circle', programOptions.defines, programOptions.vertexPragmas, programOptions.fragmentPragmas); + if (layer.paint['circle-pitch-scale'] === 'map') { + gl.uniform1i(program.u_scale_with_map, true); + gl.uniform2f(program.u_extrude_scale, painter.transform.pixelsToGLUnits[0] * painter.transform.altitude, painter.transform.pixelsToGLUnits[1] * painter.transform.altitude); + } else { + gl.uniform1i(program.u_scale_with_map, false); + gl.uniform2fv(program.u_extrude_scale, painter.transform.pixelsToGLUnits); + } + gl.uniform1f(program.u_devicepixelratio, browser.devicePixelRatio); + gl.uniformMatrix4fv(program.u_matrix, false, painter.translatePosMatrix(coord.posMatrix, tile, layer.paint['circle-translate'], layer.paint['circle-translate-anchor'])); + bucket.setUniforms(gl, 'circle', program, layer, { zoom: painter.transform.zoom }); + for (var k = 0; k < bufferGroups.length; k++) { + var group = bufferGroups[k]; + group.vaos[layer.id].bind(gl, program, group.layoutVertexBuffer, group.elementBuffer, group.paintVertexBuffers[layer.id]); + gl.drawElements(gl.TRIANGLES, group.elementBuffer.length * 3, gl.UNSIGNED_SHORT, 0); + } } - - var glyphs = {}; - var stack = this.stacks[fontstack]; - var atlas = this.atlases[fontstack]; - - // the number of pixels the sdf bitmaps are padded by - var buffer = 3; - - var missing = {}; - var remaining = 0; - var range; - - for (var i = 0; i < glyphIDs.length; i++) { - var glyphID = glyphIDs[i]; - range = Math.floor(glyphID / 256); - - if (stack[range]) { - var glyph = stack[range].glyphs[glyphID]; - var rect = atlas.addGlyph(uid, fontstack, glyph, buffer); - if (glyph) glyphs[glyphID] = new SimpleGlyph(glyph, rect, buffer); - } else { - if (missing[range] === undefined) { - missing[range] = []; - remaining++; - } - missing[range].push(glyphID); +} +},{"../util/browser":171}],91:[function(require,module,exports){ +'use strict'; +module.exports = drawCollisionDebug; +function drawCollisionDebug(painter, sourceCache, layer, coords) { + var gl = painter.gl; + gl.enable(gl.STENCIL_TEST); + var program = painter.useProgram('collisionbox'); + for (var i = 0; i < coords.length; i++) { + var coord = coords[i]; + var tile = sourceCache.getTile(coord); + var bucket = tile.getBucket(layer); + if (!bucket) + continue; + var bufferGroups = bucket.bufferGroups.collisionBox; + if (!bufferGroups || !bufferGroups.length) + continue; + var group = bufferGroups[0]; + if (group.layoutVertexBuffer.length === 0) + continue; + gl.uniformMatrix4fv(program.u_matrix, false, coord.posMatrix); + painter.enableTileClippingMask(coord); + painter.lineWidth(1); + gl.uniform1f(program.u_scale, Math.pow(2, painter.transform.zoom - tile.coord.z)); + gl.uniform1f(program.u_zoom, painter.transform.zoom * 10); + gl.uniform1f(program.u_maxzoom, (tile.coord.z + 1) * 10); + group.vaos[layer.id].bind(gl, program, group.layoutVertexBuffer); + gl.drawArrays(gl.LINES, 0, group.layoutVertexBuffer.length); + } +} +},{}],92:[function(require,module,exports){ +'use strict'; +var textVertices = require('../lib/debugtext'); +var browser = require('../util/browser'); +var mat4 = require('gl-matrix').mat4; +var EXTENT = require('../data/bucket').EXTENT; +var Buffer = require('../data/buffer'); +var VertexArrayObject = require('./vertex_array_object'); +module.exports = drawDebug; +function drawDebug(painter, sourceCache, coords) { + if (painter.isOpaquePass) + return; + if (!painter.options.debug) + return; + for (var i = 0; i < coords.length; i++) { + drawDebugTile(painter, sourceCache, coords[i]); + } +} +function drawDebugTile(painter, sourceCache, coord) { + var gl = painter.gl; + gl.disable(gl.STENCIL_TEST); + painter.lineWidth(1 * browser.devicePixelRatio); + var posMatrix = coord.posMatrix; + var program = painter.useProgram('debug'); + gl.uniformMatrix4fv(program.u_matrix, false, posMatrix); + gl.uniform4f(program.u_color, 1, 0, 0, 1); + painter.debugVAO.bind(gl, program, painter.debugBuffer); + gl.drawArrays(gl.LINE_STRIP, 0, painter.debugBuffer.length); + var vertices = textVertices(coord.toString(), 50, 200, 5); + var debugTextArray = new painter.PosArray(); + for (var v = 0; v < vertices.length; v += 2) { + debugTextArray.emplaceBack(vertices[v], vertices[v + 1]); + } + var debugTextBuffer = new Buffer(debugTextArray.serialize(), painter.PosArray.serialize(), Buffer.BufferType.VERTEX); + var debugTextVAO = new VertexArrayObject(); + debugTextVAO.bind(gl, program, debugTextBuffer); + gl.uniform4f(program.u_color, 1, 1, 1, 1); + var tileSize = sourceCache.getTile(coord).tileSize; + var onePixel = EXTENT / (Math.pow(2, painter.transform.zoom - coord.z) * tileSize); + var translations = [ + [ + -1, + -1 + ], + [ + -1, + 1 + ], + [ + 1, + -1 + ], + [ + 1, + 1 + ] + ]; + for (var i = 0; i < translations.length; i++) { + var translation = translations[i]; + gl.uniformMatrix4fv(program.u_matrix, false, mat4.translate([], posMatrix, [ + onePixel * translation[0], + onePixel * translation[1], + 0 + ])); + gl.drawArrays(gl.LINES, 0, debugTextBuffer.length); + } + gl.uniform4f(program.u_color, 0, 0, 0, 1); + gl.uniformMatrix4fv(program.u_matrix, false, posMatrix); + gl.drawArrays(gl.LINES, 0, debugTextBuffer.length); +} +},{"../data/bucket":72,"../data/buffer":77,"../lib/debugtext":86,"../util/browser":171,"./vertex_array_object":101,"gl-matrix":29}],93:[function(require,module,exports){ +'use strict'; +var pixelsToTileUnits = require('../source/pixels_to_tile_units'); +module.exports = draw; +function draw(painter, sourceCache, layer, coords) { + var gl = painter.gl; + gl.enable(gl.STENCIL_TEST); + var isOpaque; + if (layer.paint['fill-pattern']) { + isOpaque = false; + } else { + isOpaque = layer.isPaintValueFeatureConstant('fill-color') && layer.isPaintValueFeatureConstant('fill-opacity') && layer.paint['fill-color'][3] === 1 && layer.paint['fill-opacity'] === 1; + } + if (painter.isOpaquePass === isOpaque) { + painter.setDepthSublayer(1); + for (var i = 0; i < coords.length; i++) { + drawFill(painter, sourceCache, layer, coords[i]); } } - - if (!remaining) callback(undefined, glyphs, fontstack); - - var onRangeLoaded = function(err, range, data) { - // TODO not be silent about errors - if (!err) { - var stack = this.stacks[fontstack][range] = data.stacks[0]; - for (var i = 0; i < missing[range].length; i++) { - var glyphID = missing[range][i]; - var glyph = stack.glyphs[glyphID]; - var rect = atlas.addGlyph(uid, fontstack, glyph, buffer); - if (glyph) glyphs[glyphID] = new SimpleGlyph(glyph, rect, buffer); + if (!painter.isOpaquePass && layer.paint['fill-antialias']) { + painter.lineWidth(2); + painter.depthMask(false); + var isOutlineColorDefined = layer.getPaintProperty('fill-outline-color'); + if (isOutlineColorDefined || !layer.paint['fill-pattern']) { + if (isOutlineColorDefined) { + painter.setDepthSublayer(2); + } else { + painter.setDepthSublayer(0); } + } else { + painter.setDepthSublayer(0); + } + for (var j = 0; j < coords.length; j++) { + drawStroke(painter, sourceCache, layer, coords[j]); } - remaining--; - if (!remaining) callback(undefined, glyphs, fontstack); - }.bind(this); - - for (var r in missing) { - this.loadRange(fontstack, r, onRangeLoaded); } -}; - -// A simplified representation of the glyph containing only the properties needed for shaping. -function SimpleGlyph(glyph, rect, buffer) { - var padding = 1; - this.advance = glyph.advance; - this.left = glyph.left - buffer - padding; - this.top = glyph.top + buffer + padding; - this.rect = rect; } - -GlyphSource.prototype.loadRange = function(fontstack, range, callback) { - if (range * 256 > 65535) return callback('glyphs > 65535 not supported'); - - if (this.loading[fontstack] === undefined) { - this.loading[fontstack] = {}; +function drawFill(painter, sourceCache, layer, coord) { + var tile = sourceCache.getTile(coord); + var bucket = tile.getBucket(layer); + if (!bucket) + return; + var bufferGroups = bucket.bufferGroups.fill; + if (!bufferGroups) + return; + var gl = painter.gl; + var image = layer.paint['fill-pattern']; + var program; + if (!image) { + var programOptions = bucket.paintAttributes.fill[layer.id]; + program = painter.useProgram('fill', programOptions.defines, programOptions.vertexPragmas, programOptions.fragmentPragmas); + bucket.setUniforms(gl, 'fill', program, layer, { zoom: painter.transform.zoom }); + } else { + program = painter.useProgram('pattern'); + setPattern(image, layer.paint['fill-opacity'], tile, coord, painter, program); + gl.activeTexture(gl.TEXTURE0); + painter.spriteAtlas.bind(gl, true); } - var loading = this.loading[fontstack]; - - if (loading[range]) { - loading[range].push(callback); + gl.uniformMatrix4fv(program.u_matrix, false, painter.translatePosMatrix(coord.posMatrix, tile, layer.paint['fill-translate'], layer.paint['fill-translate-anchor'])); + painter.enableTileClippingMask(coord); + for (var i = 0; i < bufferGroups.length; i++) { + var group = bufferGroups[i]; + group.vaos[layer.id].bind(gl, program, group.layoutVertexBuffer, group.elementBuffer, group.paintVertexBuffers[layer.id]); + gl.drawElements(gl.TRIANGLES, group.elementBuffer.length, gl.UNSIGNED_SHORT, 0); + } +} +function drawStroke(painter, sourceCache, layer, coord) { + var tile = sourceCache.getTile(coord); + var bucket = tile.getBucket(layer); + if (!bucket) + return; + var gl = painter.gl; + var bufferGroups = bucket.bufferGroups.fill; + var image = layer.paint['fill-pattern']; + var opacity = layer.paint['fill-opacity']; + var isOutlineColorDefined = layer.getPaintProperty('fill-outline-color'); + var program; + if (image && !isOutlineColorDefined) { + program = painter.useProgram('outlinepattern'); + gl.uniform2f(program.u_world, gl.drawingBufferWidth, gl.drawingBufferHeight); } else { - loading[range] = [callback]; - - var rangeName = (range * 256) + '-' + (range * 256 + 255); - var url = glyphUrl(fontstack, rangeName, this.url); - - getArrayBuffer(url, function(err, data) { - var glyphs = !err && new Glyphs(new Protobuf(new Uint8Array(data))); - for (var i = 0; i < loading[range].length; i++) { - loading[range][i](err, range, glyphs); - } - delete loading[range]; - }); + var programOptions = bucket.paintAttributes.fill[layer.id]; + program = painter.useProgram('outline', programOptions.defines, programOptions.vertexPragmas, programOptions.fragmentPragmas); + gl.uniform2f(program.u_world, gl.drawingBufferWidth, gl.drawingBufferHeight); + gl.uniform1f(program.u_opacity, opacity); + bucket.setUniforms(gl, 'fill', program, layer, { zoom: painter.transform.zoom }); + } + gl.uniformMatrix4fv(program.u_matrix, false, painter.translatePosMatrix(coord.posMatrix, tile, layer.paint['fill-translate'], layer.paint['fill-translate-anchor'])); + if (image) { + setPattern(image, opacity, tile, coord, painter, program); + } + painter.enableTileClippingMask(coord); + for (var k = 0; k < bufferGroups.length; k++) { + var group = bufferGroups[k]; + group.secondVaos[layer.id].bind(gl, program, group.layoutVertexBuffer, group.elementBuffer2, group.paintVertexBuffers[layer.id]); + gl.drawElements(gl.LINES, group.elementBuffer2.length * 2, gl.UNSIGNED_SHORT, 0); } -}; - -GlyphSource.prototype.getGlyphAtlas = function(fontstack) { - return this.atlases[fontstack]; -}; - -/** - * Use CNAME sharding to load a specific glyph range over a randomized - * but consistent subdomain. - * @param {string} fontstack comma-joined fonts - * @param {string} range comma-joined range - * @param {url} url templated url - * @param {string} [subdomains=abc] subdomains as a string where each letter is one. - * @returns {string} a url to load that section of glyphs - * @private - */ -function glyphUrl(fontstack, range, url, subdomains) { - subdomains = subdomains || 'abc'; - - return url - .replace('{s}', subdomains[fontstack.length % subdomains.length]) - .replace('{fontstack}', fontstack) - .replace('{range}', range); } - -},{"../symbol/glyph_atlas":78,"../util/ajax":101,"../util/glyphs":108,"../util/mapbox":110,"pbf":160}],80:[function(require,module,exports){ +function setPattern(image, opacity, tile, coord, painter, program) { + var gl = painter.gl; + var imagePosA = painter.spriteAtlas.getPosition(image.from, true); + var imagePosB = painter.spriteAtlas.getPosition(image.to, true); + if (!imagePosA || !imagePosB) + return; + gl.uniform1i(program.u_image, 0); + gl.uniform2fv(program.u_pattern_tl_a, imagePosA.tl); + gl.uniform2fv(program.u_pattern_br_a, imagePosA.br); + gl.uniform2fv(program.u_pattern_tl_b, imagePosB.tl); + gl.uniform2fv(program.u_pattern_br_b, imagePosB.br); + gl.uniform1f(program.u_opacity, opacity); + gl.uniform1f(program.u_mix, image.t); + gl.uniform1f(program.u_tile_units_to_pixels, 1 / pixelsToTileUnits(tile, 1, painter.transform.tileZoom)); + gl.uniform2fv(program.u_pattern_size_a, imagePosA.size); + gl.uniform2fv(program.u_pattern_size_b, imagePosB.size); + gl.uniform1f(program.u_scale_a, image.fromScale); + gl.uniform1f(program.u_scale_b, image.toScale); + var tileSizeAtNearestZoom = tile.tileSize * Math.pow(2, painter.transform.tileZoom - tile.coord.z); + var pixelX = tileSizeAtNearestZoom * (tile.coord.x + coord.w * Math.pow(2, tile.coord.z)); + var pixelY = tileSizeAtNearestZoom * tile.coord.y; + gl.uniform2f(program.u_pixel_coord_upper, pixelX >> 16, pixelY >> 16); + gl.uniform2f(program.u_pixel_coord_lower, pixelX & 65535, pixelY & 65535); + gl.activeTexture(gl.TEXTURE0); + painter.spriteAtlas.bind(gl, true); +} +},{"../source/pixels_to_tile_units":107}],94:[function(require,module,exports){ 'use strict'; - -module.exports = function (features, textFeatures, geometries) { - - var leftIndex = {}, - rightIndex = {}, - mergedFeatures = [], - mergedGeom = [], - mergedTexts = [], - mergedIndex = 0, - k; - - function add(k) { - mergedFeatures.push(features[k]); - mergedGeom.push(geometries[k]); - mergedTexts.push(textFeatures[k]); - mergedIndex++; - } - - function mergeFromRight(leftKey, rightKey, geom) { - var i = rightIndex[leftKey]; - delete rightIndex[leftKey]; - rightIndex[rightKey] = i; - - mergedGeom[i][0].pop(); - mergedGeom[i][0] = mergedGeom[i][0].concat(geom[0]); - return i; +var browser = require('../util/browser'); +var mat2 = require('gl-matrix').mat2; +var pixelsToTileUnits = require('../source/pixels_to_tile_units'); +module.exports = function drawLine(painter, sourceCache, layer, coords) { + if (painter.isOpaquePass) + return; + painter.setDepthSublayer(0); + painter.depthMask(false); + var gl = painter.gl; + gl.enable(gl.STENCIL_TEST); + if (layer.paint['line-width'] <= 0) + return; + for (var k = 0; k < coords.length; k++) { + drawLineTile(painter, sourceCache, layer, coords[k]); } - - function mergeFromLeft(leftKey, rightKey, geom) { - var i = leftIndex[rightKey]; - delete leftIndex[rightKey]; - leftIndex[leftKey] = i; - - mergedGeom[i][0].shift(); - mergedGeom[i][0] = geom[0].concat(mergedGeom[i][0]); - return i; +}; +function drawLineTile(painter, sourceCache, layer, coord) { + var tile = sourceCache.getTile(coord); + var bucket = tile.getBucket(layer); + if (!bucket) + return; + var bufferGroups = bucket.bufferGroups.line; + if (!bufferGroups) + return; + var gl = painter.gl; + var programOptions = bucket.paintAttributes.line[layer.id]; + var antialiasing = 1 / browser.devicePixelRatio; + var blur = layer.paint['line-blur'] + antialiasing; + var color = layer.paint['line-color']; + var tr = painter.transform; + var antialiasingMatrix = mat2.create(); + mat2.scale(antialiasingMatrix, antialiasingMatrix, [ + 1, + Math.cos(tr._pitch) + ]); + mat2.rotate(antialiasingMatrix, antialiasingMatrix, painter.transform.angle); + var topedgelength = Math.sqrt(tr.height * tr.height / 4 * (1 + tr.altitude * tr.altitude)); + var x = tr.height / 2 * Math.tan(tr._pitch); + var extra = (topedgelength + x) / topedgelength - 1; + var dasharray = layer.paint['line-dasharray']; + var image = layer.paint['line-pattern']; + var program, posA, posB, imagePosA, imagePosB; + if (dasharray) { + program = painter.useProgram('linesdfpattern', programOptions.defines, programOptions.vertexPragmas, programOptions.fragmentPragmas); + gl.uniform1f(program.u_linewidth, layer.paint['line-width'] / 2); + gl.uniform1f(program.u_gapwidth, layer.paint['line-gap-width'] / 2); + gl.uniform1f(program.u_antialiasing, antialiasing / 2); + gl.uniform1f(program.u_blur, blur); + gl.uniform4fv(program.u_color, color); + gl.uniform1f(program.u_opacity, layer.paint['line-opacity']); + posA = painter.lineAtlas.getDash(dasharray.from, layer.layout['line-cap'] === 'round'); + posB = painter.lineAtlas.getDash(dasharray.to, layer.layout['line-cap'] === 'round'); + gl.uniform1i(program.u_image, 0); + gl.activeTexture(gl.TEXTURE0); + painter.lineAtlas.bind(gl); + gl.uniform1f(program.u_tex_y_a, posA.y); + gl.uniform1f(program.u_tex_y_b, posB.y); + gl.uniform1f(program.u_mix, dasharray.t); + gl.uniform1f(program.u_extra, extra); + gl.uniform1f(program.u_offset, -layer.paint['line-offset']); + gl.uniformMatrix2fv(program.u_antialiasingmatrix, false, antialiasingMatrix); + } else if (image) { + imagePosA = painter.spriteAtlas.getPosition(image.from, true); + imagePosB = painter.spriteAtlas.getPosition(image.to, true); + if (!imagePosA || !imagePosB) + return; + program = painter.useProgram('linepattern', programOptions.defines, programOptions.vertexPragmas, programOptions.fragmentPragmas); + gl.uniform1i(program.u_image, 0); + gl.activeTexture(gl.TEXTURE0); + painter.spriteAtlas.bind(gl, true); + gl.uniform1f(program.u_linewidth, layer.paint['line-width'] / 2); + gl.uniform1f(program.u_gapwidth, layer.paint['line-gap-width'] / 2); + gl.uniform1f(program.u_antialiasing, antialiasing / 2); + gl.uniform1f(program.u_blur, blur); + gl.uniform2fv(program.u_pattern_tl_a, imagePosA.tl); + gl.uniform2fv(program.u_pattern_br_a, imagePosA.br); + gl.uniform2fv(program.u_pattern_tl_b, imagePosB.tl); + gl.uniform2fv(program.u_pattern_br_b, imagePosB.br); + gl.uniform1f(program.u_fade, image.t); + gl.uniform1f(program.u_opacity, layer.paint['line-opacity']); + gl.uniform1f(program.u_extra, extra); + gl.uniform1f(program.u_offset, -layer.paint['line-offset']); + gl.uniformMatrix2fv(program.u_antialiasingmatrix, false, antialiasingMatrix); + } else { + program = painter.useProgram('line', programOptions.defines, programOptions.vertexPragmas, programOptions.fragmentPragmas); + gl.uniform1f(program.u_linewidth, layer.paint['line-width'] / 2); + gl.uniform1f(program.u_gapwidth, layer.paint['line-gap-width'] / 2); + gl.uniform1f(program.u_antialiasing, antialiasing / 2); + gl.uniform1f(program.u_blur, blur); + gl.uniform1f(program.u_extra, extra); + gl.uniform1f(program.u_offset, -layer.paint['line-offset']); + gl.uniformMatrix2fv(program.u_antialiasingmatrix, false, antialiasingMatrix); + gl.uniform4fv(program.u_color, color); + gl.uniform1f(program.u_opacity, layer.paint['line-opacity']); } - - function getKey(text, geom, onRight) { - var point = onRight ? geom[0][geom[0].length - 1] : geom[0][0]; - return text + ':' + point.x + ':' + point.y; + painter.enableTileClippingMask(coord); + var posMatrix = painter.translatePosMatrix(coord.posMatrix, tile, layer.paint['line-translate'], layer.paint['line-translate-anchor']); + gl.uniformMatrix4fv(program.u_matrix, false, posMatrix); + var ratio = 1 / pixelsToTileUnits(tile, 1, painter.transform.zoom); + if (dasharray) { + var widthA = posA.width * dasharray.fromScale; + var widthB = posB.width * dasharray.toScale; + var scaleA = [ + 1 / pixelsToTileUnits(tile, widthA, painter.transform.tileZoom), + -posA.height / 2 + ]; + var scaleB = [ + 1 / pixelsToTileUnits(tile, widthB, painter.transform.tileZoom), + -posB.height / 2 + ]; + var gamma = painter.lineAtlas.width / (Math.min(widthA, widthB) * 256 * browser.devicePixelRatio) / 2; + gl.uniform1f(program.u_ratio, ratio); + gl.uniform2fv(program.u_patternscale_a, scaleA); + gl.uniform2fv(program.u_patternscale_b, scaleB); + gl.uniform1f(program.u_sdfgamma, gamma); + } else if (image) { + gl.uniform1f(program.u_ratio, ratio); + gl.uniform2fv(program.u_pattern_size_a, [ + pixelsToTileUnits(tile, imagePosA.size[0] * image.fromScale, painter.transform.tileZoom), + imagePosB.size[1] + ]); + gl.uniform2fv(program.u_pattern_size_b, [ + pixelsToTileUnits(tile, imagePosB.size[0] * image.toScale, painter.transform.tileZoom), + imagePosB.size[1] + ]); + } else { + gl.uniform1f(program.u_ratio, ratio); } - - for (k = 0; k < features.length; k++) { - var geom = geometries[k], - text = textFeatures[k]; - - if (!text) { - add(k); - continue; - } - - var leftKey = getKey(text, geom), - rightKey = getKey(text, geom, true); - - if ((leftKey in rightIndex) && (rightKey in leftIndex) && (rightIndex[leftKey] !== leftIndex[rightKey])) { - // found lines with the same text adjacent to both ends of the current line, merge all three - var j = mergeFromLeft(leftKey, rightKey, geom); - var i = mergeFromRight(leftKey, rightKey, mergedGeom[j]); - - delete leftIndex[leftKey]; - delete rightIndex[rightKey]; - - rightIndex[getKey(text, mergedGeom[i], true)] = i; - mergedGeom[j] = null; - - } else if (leftKey in rightIndex) { - // found mergeable line adjacent to the start of the current line, merge - mergeFromRight(leftKey, rightKey, geom); - - } else if (rightKey in leftIndex) { - // found mergeable line adjacent to the end of the current line, merge - mergeFromLeft(leftKey, rightKey, geom); - - } else { - // no adjacent lines, add as a new item - add(k); - leftIndex[leftKey] = mergedIndex - 1; - rightIndex[rightKey] = mergedIndex - 1; - } + bucket.setUniforms(gl, 'line', program, layer, { zoom: painter.transform.zoom }); + for (var i = 0; i < bufferGroups.length; i++) { + var group = bufferGroups[i]; + group.vaos[layer.id].bind(gl, program, group.layoutVertexBuffer, group.elementBuffer, group.paintVertexBuffers[layer.id]); + gl.drawElements(gl.TRIANGLES, group.elementBuffer.length * 3, gl.UNSIGNED_SHORT, 0); } - - return { - features: mergedFeatures, - textFeatures: mergedTexts, - geometries: mergedGeom - }; -}; - -},{}],81:[function(require,module,exports){ +} +},{"../source/pixels_to_tile_units":107,"../util/browser":171,"gl-matrix":29}],95:[function(require,module,exports){ 'use strict'; - -var Point = require('point-geometry'); - -module.exports = { - getIconQuads: getIconQuads, - getGlyphQuads: getGlyphQuads -}; - -var minScale = 0.5; // underscale by 1 zoom level - -/** - * A textured quad for rendering a single icon or glyph. - * - * The zoom range the glyph can be shown is defined by minScale and maxScale. - * - * @param {Point} anchorPoint the point the symbol is anchored around - * @param {Point} tl The offset of the top left corner from the anchor. - * @param {Point} tr The offset of the top right corner from the anchor. - * @param {Point} bl The offset of the bottom left corner from the anchor. - * @param {Point} br The offset of the bottom right corner from the anchor. - * @param {Object} tex The texture coordinates. - * @param {number} angle The angle of the label at it's center, not the angle of this quad. - * @param {number} minScale The minimum scale, relative to the tile's intended scale, that the glyph can be shown at. - * @param {number} maxScale The maximum scale, relative to the tile's intended scale, that the glyph can be shown at. - * - * @class SymbolQuad - * @private - */ -function SymbolQuad(anchorPoint, tl, tr, bl, br, tex, angle, minScale, maxScale) { - this.anchorPoint = anchorPoint; - this.tl = tl; - this.tr = tr; - this.bl = bl; - this.br = br; - this.tex = tex; - this.angle = angle; - this.minScale = minScale; - this.maxScale = maxScale; -} - -/** - * Create the quads used for rendering an icon. - * - * @param {Anchor} anchor - * @param {PositionedIcon} shapedIcon - * @param {number} boxScale A magic number for converting glyph metric units to geometry units. - * @param {Array>} line - * @param {LayoutProperties} layout - * @param {boolean} alongLine Whether the icon should be placed along the line. - * @returns {Array} - * @private - */ -function getIconQuads(anchor, shapedIcon, boxScale, line, layout, alongLine) { - - var rect = shapedIcon.image.rect; - - var border = 1; - var left = shapedIcon.left - border; - var right = left + rect.w / shapedIcon.image.pixelRatio; - var top = shapedIcon.top - border; - var bottom = top + rect.h / shapedIcon.image.pixelRatio; - var tl = new Point(left, top); - var tr = new Point(right, top); - var br = new Point(right, bottom); - var bl = new Point(left, bottom); - - var angle = layout['icon-rotate'] * Math.PI / 180; - if (alongLine) { - var prev = line[anchor.segment]; - if (anchor.y === prev.y && anchor.x === prev.x && anchor.segment + 1 < line.length) { - var next = line[anchor.segment + 1]; - angle += Math.atan2(anchor.y - next.y, anchor.x - next.x) + Math.PI; - } else { - angle += Math.atan2(anchor.y - prev.y, anchor.x - prev.x); - } - } - - if (angle) { - var sin = Math.sin(angle), - cos = Math.cos(angle), - matrix = [cos, -sin, sin, cos]; - - tl = tl.matMult(matrix); - tr = tr.matMult(matrix); - bl = bl.matMult(matrix); - br = br.matMult(matrix); +var util = require('../util/util'); +var StructArrayType = require('../util/struct_array'); +module.exports = drawRaster; +function drawRaster(painter, sourceCache, layer, coords) { + if (painter.isOpaquePass) + return; + var gl = painter.gl; + gl.enable(gl.DEPTH_TEST); + painter.depthMask(true); + gl.depthFunc(gl.LESS); + var minTileZ = coords.length && coords[0].z; + for (var i = 0; i < coords.length; i++) { + var coord = coords[i]; + painter.setDepthSublayer(coord.z - minTileZ); + drawRasterTile(painter, sourceCache, layer, coord); } - - return [new SymbolQuad(new Point(anchor.x, anchor.y), tl, tr, bl, br, shapedIcon.image.rect, 0, minScale, Infinity)]; + gl.depthFunc(gl.LEQUAL); } - -/** - * Create the quads used for rendering a text label. - * - * @param {Anchor} anchor - * @param {Shaping} shaping - * @param {number} boxScale A magic number for converting from glyph metric units to geometry units. - * @param {Array>} line - * @param {LayoutProperties} layout - * @param {boolean} alongLine Whether the label should be placed along the line. - * @returns {Array} - * @private - */ -function getGlyphQuads(anchor, shaping, boxScale, line, layout, alongLine) { - - var textRotate = layout['text-rotate'] * Math.PI / 180; - var keepUpright = layout['text-keep-upright']; - - var positionedGlyphs = shaping.positionedGlyphs; - var quads = []; - - for (var k = 0; k < positionedGlyphs.length; k++) { - var positionedGlyph = positionedGlyphs[k]; - var glyph = positionedGlyph.glyph; - var rect = glyph.rect; - - if (!rect) continue; - - var centerX = (positionedGlyph.x + glyph.advance / 2) * boxScale; - - var glyphInstances; - var labelMinScale = minScale; - if (alongLine) { - glyphInstances = []; - labelMinScale = getSegmentGlyphs(glyphInstances, anchor, centerX, line, anchor.segment, true); - if (keepUpright) { - labelMinScale = Math.min(labelMinScale, getSegmentGlyphs(glyphInstances, anchor, centerX, line, anchor.segment, false)); - } - - } else { - glyphInstances = [{ - anchorPoint: new Point(anchor.x, anchor.y), - offset: 0, - angle: 0, - maxScale: Infinity, - minScale: minScale - }]; - } - - var x1 = positionedGlyph.x + glyph.left, - y1 = positionedGlyph.y - glyph.top, - x2 = x1 + rect.w, - y2 = y1 + rect.h, - - otl = new Point(x1, y1), - otr = new Point(x2, y1), - obl = new Point(x1, y2), - obr = new Point(x2, y2); - - for (var i = 0; i < glyphInstances.length; i++) { - - var instance = glyphInstances[i], - tl = otl, - tr = otr, - bl = obl, - br = obr, - angle = instance.angle + textRotate; - - if (angle) { - var sin = Math.sin(angle), - cos = Math.cos(angle), - matrix = [cos, -sin, sin, cos]; - - tl = tl.matMult(matrix); - tr = tr.matMult(matrix); - bl = bl.matMult(matrix); - br = br.matMult(matrix); - } - - // Prevent label from extending past the end of the line - var glyphMinScale = Math.max(instance.minScale, labelMinScale); - - var glyphAngle = (anchor.angle + textRotate + instance.offset + 2 * Math.PI) % (2 * Math.PI); - quads.push(new SymbolQuad(instance.anchorPoint, tl, tr, bl, br, rect, glyphAngle, glyphMinScale, instance.maxScale)); - +drawRaster.RasterBoundsArray = new StructArrayType({ + members: [ + { + name: 'a_pos', + type: 'Int16', + components: 2 + }, + { + name: 'a_texture_pos', + type: 'Int16', + components: 2 } + ] +}); +function drawRasterTile(painter, sourceCache, layer, coord) { + var gl = painter.gl; + gl.disable(gl.STENCIL_TEST); + var tile = sourceCache.getTile(coord); + var posMatrix = painter.transform.calculatePosMatrix(coord, sourceCache.getSource().maxzoom); + var program = painter.useProgram('raster'); + gl.uniformMatrix4fv(program.u_matrix, false, posMatrix); + gl.uniform1f(program.u_brightness_low, layer.paint['raster-brightness-min']); + gl.uniform1f(program.u_brightness_high, layer.paint['raster-brightness-max']); + gl.uniform1f(program.u_saturation_factor, saturationFactor(layer.paint['raster-saturation'])); + gl.uniform1f(program.u_contrast_factor, contrastFactor(layer.paint['raster-contrast'])); + gl.uniform3fv(program.u_spin_weights, spinWeights(layer.paint['raster-hue-rotate'])); + var parentTile = tile.sourceCache && tile.sourceCache.findLoadedParent(coord, 0, {}), opacities = getOpacities(tile, parentTile, layer, painter.transform); + var parentScaleBy, parentTL; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, tile.texture); + gl.activeTexture(gl.TEXTURE1); + if (parentTile) { + gl.bindTexture(gl.TEXTURE_2D, parentTile.texture); + parentScaleBy = Math.pow(2, parentTile.coord.z - tile.coord.z); + parentTL = [ + tile.coord.x * parentScaleBy % 1, + tile.coord.y * parentScaleBy % 1 + ]; + } else { + gl.bindTexture(gl.TEXTURE_2D, tile.texture); + opacities[1] = 0; } - - return quads; + gl.uniform2fv(program.u_tl_parent, parentTL || [ + 0, + 0 + ]); + gl.uniform1f(program.u_scale_parent, parentScaleBy || 1); + gl.uniform1f(program.u_buffer_scale, 1); + gl.uniform1f(program.u_opacity0, opacities[0]); + gl.uniform1f(program.u_opacity1, opacities[1]); + gl.uniform1i(program.u_image0, 0); + gl.uniform1i(program.u_image1, 1); + var buffer = tile.boundsBuffer || painter.rasterBoundsBuffer; + var vao = tile.boundsVAO || painter.rasterBoundsVAO; + vao.bind(gl, program, buffer); + gl.drawArrays(gl.TRIANGLE_STRIP, 0, buffer.length); } - -/** - * We can only render glyph quads that slide along a straight line. To draw - * curved lines we need an instance of a glyph for each segment it appears on. - * This creates all the instances of a glyph that are necessary to render a label. - * - * We need a - * @param {Array} glyphInstances An empty array that glyphInstances are added to. - * @param {Anchor} anchor - * @param {number} offset The glyph's offset from the center of the label. - * @param {Array} line - * @param {number} segment The index of the segment of the line on which the anchor exists. - * @param {boolean} forward If true get the glyphs that come later on the line, otherwise get the glyphs that come earlier. - * - * @returns {Array} glyphInstances - * @private - */ -function getSegmentGlyphs(glyphs, anchor, offset, line, segment, forward) { - var upsideDown = !forward; - - if (offset < 0) forward = !forward; - - if (forward) segment++; - - var newAnchorPoint = new Point(anchor.x, anchor.y); - var end = line[segment]; - var prevScale = Infinity; - - offset = Math.abs(offset); - - var placementScale = minScale; - - while (true) { - var distance = newAnchorPoint.dist(end); - var scale = offset / distance; - - // Get the angle of the line segment - var angle = Math.atan2(end.y - newAnchorPoint.y, end.x - newAnchorPoint.x); - if (!forward) angle += Math.PI; - if (upsideDown) angle += Math.PI; - - glyphs.push({ - anchorPoint: newAnchorPoint, - offset: upsideDown ? Math.PI : 0, - minScale: scale, - maxScale: prevScale, - angle: (angle + 2 * Math.PI) % (2 * Math.PI) +function spinWeights(angle) { + angle *= Math.PI / 180; + var s = Math.sin(angle); + var c = Math.cos(angle); + return [ + (2 * c + 1) / 3, + (-Math.sqrt(3) * s - c + 1) / 3, + (Math.sqrt(3) * s - c + 1) / 3 + ]; +} +function contrastFactor(contrast) { + return contrast > 0 ? 1 / (1 - contrast) : 1 + contrast; +} +function saturationFactor(saturation) { + return saturation > 0 ? 1 - 1 / (1.001 - saturation) : -saturation; +} +function getOpacities(tile, parentTile, layer, transform) { + var opacity = [ + 1, + 0 + ]; + var fadeDuration = layer.paint['raster-fade-duration']; + if (tile.sourceCache && fadeDuration > 0) { + var now = new Date().getTime(); + var sinceTile = (now - tile.timeAdded) / fadeDuration; + var sinceParent = parentTile ? (now - parentTile.timeAdded) / fadeDuration : -1; + var idealZ = transform.coveringZoomLevel({ + tileSize: tile.sourceCache.getSource().tileSize, + roundZoom: tile.sourceCache.getSource().roundZoom }); - - if (scale <= placementScale) break; - - newAnchorPoint = end; - - // skip duplicate nodes - while (newAnchorPoint.equals(end)) { - segment += forward ? 1 : -1; - end = line[segment]; - if (!end) { - return scale; - } + var parentFurther = parentTile ? Math.abs(parentTile.coord.z - idealZ) > Math.abs(tile.coord.z - idealZ) : false; + if (!parentTile || parentFurther) { + opacity[0] = util.clamp(sinceTile, 0, 1); + opacity[1] = 1 - opacity[0]; + } else { + opacity[0] = util.clamp(1 - sinceParent, 0, 1); + opacity[1] = 1 - opacity[0]; } - - var unit = end.sub(newAnchorPoint)._unit(); - newAnchorPoint = newAnchorPoint.sub(unit._mult(distance)); - - prevScale = scale; } - - return placementScale; + var op = layer.paint['raster-opacity']; + opacity[0] *= op; + opacity[1] *= op; + return opacity; } - -},{"point-geometry":162}],82:[function(require,module,exports){ +},{"../util/struct_array":186,"../util/util":188}],96:[function(require,module,exports){ 'use strict'; - -var resolveTokens = require('../util/token'); - -module.exports = resolveText; - -/** - * For an array of features determine what glyphs need to be loaded - * and apply any text preprocessing. The remaining users of text should - * use the `textFeatures` key returned by this function rather than accessing - * feature text directly. - * @private - */ -function resolveText(features, layoutProperties, codepoints) { - var textFeatures = []; - - for (var i = 0, fl = features.length; i < fl; i++) { - var text = resolveTokens(features[i].properties, layoutProperties['text-field']); - if (!text) { - textFeatures[i] = null; +var browser = require('../util/browser'); +var drawCollisionDebug = require('./draw_collision_debug'); +var pixelsToTileUnits = require('../source/pixels_to_tile_units'); +module.exports = drawSymbols; +function drawSymbols(painter, sourceCache, layer, coords) { + if (painter.isOpaquePass) + return; + var drawAcrossEdges = !(layer.layout['text-allow-overlap'] || layer.layout['icon-allow-overlap'] || layer.layout['text-ignore-placement'] || layer.layout['icon-ignore-placement']); + var gl = painter.gl; + if (drawAcrossEdges) { + gl.disable(gl.STENCIL_TEST); + } else { + gl.enable(gl.STENCIL_TEST); + } + painter.setDepthSublayer(0); + painter.depthMask(false); + gl.disable(gl.DEPTH_TEST); + drawLayerSymbols(painter, sourceCache, layer, coords, false, layer.paint['icon-translate'], layer.paint['icon-translate-anchor'], layer.layout['icon-rotation-alignment'], layer.layout['icon-rotation-alignment'], layer.layout['icon-size'], layer.paint['icon-halo-width'], layer.paint['icon-halo-color'], layer.paint['icon-halo-blur'], layer.paint['icon-opacity'], layer.paint['icon-color']); + drawLayerSymbols(painter, sourceCache, layer, coords, true, layer.paint['text-translate'], layer.paint['text-translate-anchor'], layer.layout['text-rotation-alignment'], layer.layout['text-pitch-alignment'], layer.layout['text-size'], layer.paint['text-halo-width'], layer.paint['text-halo-color'], layer.paint['text-halo-blur'], layer.paint['text-opacity'], layer.paint['text-color']); + gl.enable(gl.DEPTH_TEST); + if (sourceCache.map.showCollisionBoxes) { + drawCollisionDebug(painter, sourceCache, layer, coords); + } +} +function drawLayerSymbols(painter, sourceCache, layer, coords, isText, translate, translateAnchor, rotationAlignment, pitchAlignment, size, haloWidth, haloColor, haloBlur, opacity, color) { + for (var j = 0; j < coords.length; j++) { + var tile = sourceCache.getTile(coords[j]); + var bucket = tile.getBucket(layer); + if (!bucket) continue; - } - text = text.toString(); - - var transform = layoutProperties['text-transform']; - if (transform === 'uppercase') { - text = text.toLocaleUpperCase(); - } else if (transform === 'lowercase') { - text = text.toLocaleLowerCase(); - } - - for (var j = 0; j < text.length; j++) { - codepoints[text.charCodeAt(j)] = true; - } - - // Track indexes of features with text. - textFeatures[i] = text; + var bothBufferGroups = bucket.bufferGroups; + var bufferGroups = isText ? bothBufferGroups.glyph : bothBufferGroups.icon; + if (!bufferGroups.length) + continue; + painter.enableTileClippingMask(coords[j]); + drawSymbol(painter, layer, coords[j].posMatrix, tile, bucket, bufferGroups, isText, isText || bucket.sdfIcons, !isText && bucket.iconsNeedLinear, isText ? bucket.adjustedTextSize : bucket.adjustedIconSize, bucket.fontstack, translate, translateAnchor, rotationAlignment, pitchAlignment, size, haloWidth, haloColor, haloBlur, opacity, color); } - - return textFeatures; } - -},{"../util/token":112}],83:[function(require,module,exports){ -'use strict'; - -module.exports = { - shapeText: shapeText, - shapeIcon: shapeIcon -}; - - -// The position of a glyph relative to the text's anchor point. -function PositionedGlyph(codePoint, x, y, glyph) { - this.codePoint = codePoint; - this.x = x; - this.y = y; - this.glyph = glyph; -} - -// A collection of positioned glyphs and some metadata -function Shaping(positionedGlyphs, text, top, bottom, left, right) { - this.positionedGlyphs = positionedGlyphs; - this.text = text; - this.top = top; - this.bottom = bottom; - this.left = left; - this.right = right; -} - -function shapeText(text, glyphs, maxWidth, lineHeight, horizontalAlign, verticalAlign, justify, spacing, translate) { - - var positionedGlyphs = []; - var shaping = new Shaping(positionedGlyphs, text, translate[1], translate[1], translate[0], translate[0]); - - // the y offset *should* be part of the font metadata - var yOffset = -17; - - var x = 0; - var y = yOffset; - - for (var i = 0; i < text.length; i++) { - var codePoint = text.charCodeAt(i); - var glyph = glyphs[codePoint]; - - if (!glyph) continue; - - positionedGlyphs.push(new PositionedGlyph(codePoint, x, y, glyph)); - x += glyph.advance + spacing; +function drawSymbol(painter, layer, posMatrix, tile, bucket, bufferGroups, isText, sdf, iconsNeedLinear, adjustedSize, fontstack, translate, translateAnchor, rotationAlignment, pitchAlignment, size, haloWidth, haloColor, haloBlur, opacity, color) { + var gl = painter.gl; + var tr = painter.transform; + var rotateWithMap = rotationAlignment === 'map'; + var pitchWithMap = pitchAlignment === 'map'; + var defaultSize = isText ? 24 : 1; + var fontScale = size / defaultSize; + var extrudeScale, s, gammaScale; + if (pitchWithMap) { + s = pixelsToTileUnits(tile, 1, painter.transform.zoom) * fontScale; + gammaScale = 1 / Math.cos(tr._pitch); + extrudeScale = [ + s, + s + ]; + } else { + s = painter.transform.altitude * fontScale; + gammaScale = 1; + extrudeScale = [ + tr.pixelsToGLUnits[0] * s, + tr.pixelsToGLUnits[1] * s + ]; } - - if (!positionedGlyphs.length) return false; - - linewrap(shaping, glyphs, lineHeight, maxWidth, horizontalAlign, verticalAlign, justify, translate); - - return shaping; -} - -var invisible = { - 0x20: true, // space - 0x200b: true // zero-width space -}; - -var breakable = { - 0x20: true, // space - 0x26: true, // ampersand - 0x2b: true, // plus sign - 0x2d: true, // hyphen-minus - 0x2f: true, // solidus - 0xad: true, // soft hyphen - 0xb7: true, // middle dot - 0x200b: true, // zero-width space - 0x2010: true, // hyphen - 0x2013: true // en dash -}; - -function linewrap(shaping, glyphs, lineHeight, maxWidth, horizontalAlign, verticalAlign, justify, translate) { - var lastSafeBreak = null; - - var lengthBeforeCurrentLine = 0; - var lineStartIndex = 0; - var line = 0; - - var maxLineLength = 0; - - var positionedGlyphs = shaping.positionedGlyphs; - - if (maxWidth) { - for (var i = 0; i < positionedGlyphs.length; i++) { - var positionedGlyph = positionedGlyphs[i]; - - positionedGlyph.x -= lengthBeforeCurrentLine; - positionedGlyph.y += lineHeight * line; - - if (positionedGlyph.x > maxWidth && lastSafeBreak !== null) { - - var lineLength = positionedGlyphs[lastSafeBreak + 1].x; - maxLineLength = Math.max(lineLength, maxLineLength); - - for (var k = lastSafeBreak + 1; k <= i; k++) { - positionedGlyphs[k].y += lineHeight; - positionedGlyphs[k].x -= lineLength; - } - - if (justify) { - // Collapse invisible characters. - var lineEnd = lastSafeBreak; - if (invisible[positionedGlyphs[lastSafeBreak].codePoint]) { - lineEnd--; - } - - justifyLine(positionedGlyphs, glyphs, lineStartIndex, lineEnd, justify); - } - - lineStartIndex = lastSafeBreak + 1; - lastSafeBreak = null; - lengthBeforeCurrentLine += lineLength; - line++; - } - - if (breakable[positionedGlyph.codePoint]) { - lastSafeBreak = i; + if (!isText && !painter.style.sprite.loaded()) + return; + var program = painter.useProgram(sdf ? 'sdf' : 'icon'); + gl.uniformMatrix4fv(program.u_matrix, false, painter.translatePosMatrix(posMatrix, tile, translate, translateAnchor)); + gl.uniform1i(program.u_rotate_with_map, rotateWithMap); + gl.uniform1i(program.u_pitch_with_map, pitchWithMap); + gl.uniform2fv(program.u_extrude_scale, extrudeScale); + gl.activeTexture(gl.TEXTURE0); + gl.uniform1i(program.u_texture, 0); + if (isText) { + var glyphAtlas = fontstack && painter.glyphSource.getGlyphAtlas(fontstack); + if (!glyphAtlas) + return; + glyphAtlas.updateTexture(gl); + gl.uniform2f(program.u_texsize, glyphAtlas.width / 4, glyphAtlas.height / 4); + } else { + var mapMoving = painter.options.rotating || painter.options.zooming; + var iconScaled = fontScale !== 1 || browser.devicePixelRatio !== painter.spriteAtlas.pixelRatio || iconsNeedLinear; + var iconTransformed = pitchWithMap || painter.transform.pitch; + painter.spriteAtlas.bind(gl, sdf || mapMoving || iconScaled || iconTransformed); + gl.uniform2f(program.u_texsize, painter.spriteAtlas.width / 4, painter.spriteAtlas.height / 4); + } + var zoomAdjust = Math.log(size / adjustedSize) / Math.LN2 || 0; + gl.uniform1f(program.u_zoom, (painter.transform.zoom - zoomAdjust) * 10); + gl.activeTexture(gl.TEXTURE1); + painter.frameHistory.bind(gl); + gl.uniform1i(program.u_fadetexture, 1); + var group; + if (sdf) { + var sdfPx = 8; + var blurOffset = 1.19; + var haloOffset = 6; + var gamma = 0.105 * defaultSize / size / browser.devicePixelRatio; + if (haloWidth) { + gl.uniform1f(program.u_gamma, (haloBlur * blurOffset / fontScale / sdfPx + gamma) * gammaScale); + gl.uniform4fv(program.u_color, haloColor); + gl.uniform1f(program.u_opacity, opacity); + gl.uniform1f(program.u_buffer, (haloOffset - haloWidth / fontScale) / sdfPx); + for (var j = 0; j < bufferGroups.length; j++) { + group = bufferGroups[j]; + group.vaos[layer.id].bind(gl, program, group.layoutVertexBuffer, group.elementBuffer); + gl.drawElements(gl.TRIANGLES, group.elementBuffer.length * 3, gl.UNSIGNED_SHORT, 0); } } + gl.uniform1f(program.u_gamma, gamma * gammaScale); + gl.uniform4fv(program.u_color, color); + gl.uniform1f(program.u_opacity, opacity); + gl.uniform1f(program.u_buffer, (256 - 64) / 256); + gl.uniform1f(program.u_pitch, tr.pitch / 360 * 2 * Math.PI); + gl.uniform1f(program.u_bearing, tr.bearing / 360 * 2 * Math.PI); + gl.uniform1f(program.u_aspect_ratio, tr.width / tr.height); + for (var i = 0; i < bufferGroups.length; i++) { + group = bufferGroups[i]; + group.vaos[layer.id].bind(gl, program, group.layoutVertexBuffer, group.elementBuffer); + gl.drawElements(gl.TRIANGLES, group.elementBuffer.length * 3, gl.UNSIGNED_SHORT, 0); + } + } else { + gl.uniform1f(program.u_opacity, opacity); + for (var k = 0; k < bufferGroups.length; k++) { + group = bufferGroups[k]; + group.vaos[layer.id].bind(gl, program, group.layoutVertexBuffer, group.elementBuffer); + gl.drawElements(gl.TRIANGLES, group.elementBuffer.length * 3, gl.UNSIGNED_SHORT, 0); + } } - - var lastPositionedGlyph = positionedGlyphs[positionedGlyphs.length - 1]; - var lastLineLength = lastPositionedGlyph.x + glyphs[lastPositionedGlyph.codePoint].advance; - maxLineLength = Math.max(maxLineLength, lastLineLength); - - var height = (line + 1) * lineHeight; - - justifyLine(positionedGlyphs, glyphs, lineStartIndex, positionedGlyphs.length - 1, justify); - align(positionedGlyphs, justify, horizontalAlign, verticalAlign, maxLineLength, lineHeight, line, translate); - - // Calculate the bounding box - shaping.top += -verticalAlign * height; - shaping.bottom = shaping.top + height; - shaping.left += -horizontalAlign * maxLineLength; - shaping.right = shaping.left + maxLineLength; -} - -function justifyLine(positionedGlyphs, glyphs, start, end, justify) { - var lastAdvance = glyphs[positionedGlyphs[end].codePoint].advance; - var lineIndent = (positionedGlyphs[end].x + lastAdvance) * justify; - - for (var j = start; j <= end; j++) { - positionedGlyphs[j].x -= lineIndent; - } - -} - -function align(positionedGlyphs, justify, horizontalAlign, verticalAlign, maxLineLength, lineHeight, line, translate) { - var shiftX = (justify - horizontalAlign) * maxLineLength + translate[0]; - var shiftY = (-verticalAlign * (line + 1) + 0.5) * lineHeight + translate[1]; - - for (var j = 0; j < positionedGlyphs.length; j++) { - positionedGlyphs[j].x += shiftX; - positionedGlyphs[j].y += shiftY; - } -} - - -function shapeIcon(image, layout) { - if (!image || !image.rect) return null; - - var dx = layout['icon-offset'][0]; - var dy = layout['icon-offset'][1]; - var x1 = dx - image.width / 2; - var x2 = x1 + image.width; - var y1 = dy - image.height / 2; - var y2 = y1 + image.height; - - return new PositionedIcon(image, y1, y2, x1, x2); -} - -function PositionedIcon(image, top, bottom, left, right) { - this.image = image; - this.top = top; - this.bottom = bottom; - this.left = left; - this.right = right; } - -},{}],84:[function(require,module,exports){ +},{"../source/pixels_to_tile_units":107,"../util/browser":171,"./draw_collision_debug":91}],97:[function(require,module,exports){ 'use strict'; - -var ShelfPack = require('shelf-pack'); -var browser = require('../util/browser'); - -module.exports = SpriteAtlas; -function SpriteAtlas(width, height) { - this.width = width; - this.height = height; - - this.bin = new ShelfPack(width, height); - this.images = {}; - this.data = false; - this.texture = 0; // WebGL ID - this.filter = 0; // WebGL ID - this.pixelRatio = 1; - this.dirty = true; -} - -SpriteAtlas.prototype = { - get debug() { - return 'canvas' in this; - }, - set debug(value) { - if (value && !this.canvas) { - this.canvas = document.createElement('canvas'); - this.canvas.width = this.width * this.pixelRatio; - this.canvas.height = this.height * this.pixelRatio; - this.canvas.style.width = this.width + 'px'; - this.canvas.style.width = this.width + 'px'; - document.body.appendChild(this.canvas); - this.ctx = this.canvas.getContext('2d'); - } else if (!value && this.canvas) { - this.canvas.parentNode.removeChild(this.canvas); - delete this.ctx; - delete this.canvas; +module.exports = FrameHistory; +function FrameHistory() { + this.changeTimes = new Float64Array(256); + this.changeOpacities = new Uint8Array(256); + this.opacities = new Uint8ClampedArray(256); + this.array = new Uint8Array(this.opacities.buffer); + this.fadeDuration = 300; + this.previousZoom = 0; + this.firstFrame = true; +} +FrameHistory.prototype.record = function (zoom) { + var now = Date.now(); + if (this.firstFrame) { + now = 0; + this.firstFrame = false; + } + zoom = Math.floor(zoom * 10); + var z; + if (zoom < this.previousZoom) { + for (z = zoom + 1; z <= this.previousZoom; z++) { + this.changeTimes[z] = now; + this.changeOpacities[z] = this.opacities[z]; + } + } else { + for (z = zoom; z > this.previousZoom; z--) { + this.changeTimes[z] = now; + this.changeOpacities[z] = this.opacities[z]; } } -}; - -function copyBitmap(src, srcStride, srcX, srcY, dst, dstStride, dstX, dstY, width, height, wrap) { - var srcI = srcY * srcStride + srcX; - var dstI = dstY * dstStride + dstX; - var x, y; - - if (wrap) { - // add 1 pixel wrapped padding on each side of the image - dstI -= dstStride; - for (y = -1; y <= height; y++, srcI = ((y + height) % height + srcY) * srcStride + srcX, dstI += dstStride) { - for (x = -1; x <= width; x++) { - dst[dstI + x] = src[srcI + ((x + width) % width)]; - } + for (z = 0; z < 256; z++) { + var timeSince = now - this.changeTimes[z]; + var opacityChange = timeSince / this.fadeDuration * 255; + if (z <= zoom) { + this.opacities[z] = this.changeOpacities[z] + opacityChange; + } else { + this.opacities[z] = this.changeOpacities[z] - opacityChange; } - + } + this.changed = true; + this.previousZoom = zoom; +}; +FrameHistory.prototype.bind = function (gl) { + if (!this.texture) { + this.texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this.texture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.ALPHA, 256, 1, 0, gl.ALPHA, gl.UNSIGNED_BYTE, this.array); } else { - for (y = 0; y < height; y++, srcI += srcStride, dstI += dstStride) { - for (x = 0; x < width; x++) { - dst[dstI + x] = src[srcI + x]; - } + gl.bindTexture(gl.TEXTURE_2D, this.texture); + if (this.changed) { + gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 256, 1, gl.ALPHA, gl.UNSIGNED_BYTE, this.array); + this.changed = false; } } +}; +},{}],98:[function(require,module,exports){ +'use strict'; +var util = require('../util/util'); +module.exports = LineAtlas; +function LineAtlas(width, height) { + this.width = width; + this.height = height; + this.nextRow = 0; + this.bytes = 4; + this.data = new Uint8Array(this.width * this.height * this.bytes); + this.positions = {}; } - -SpriteAtlas.prototype.allocateImage = function(pixelWidth, pixelHeight) { - - pixelWidth = pixelWidth / this.pixelRatio; - pixelHeight = pixelHeight / this.pixelRatio; - - // Increase to next number divisible by 4, but at least 1. - // This is so we can scale down the texture coordinates and pack them - // into 2 bytes rather than 4 bytes. - // Pad icons to prevent them from polluting neighbours during linear interpolation - var padding = 2; - var packWidth = pixelWidth + padding + (4 - (pixelWidth + padding) % 4); - var packHeight = pixelHeight + padding + (4 - (pixelHeight + padding) % 4);// + 4; - - // We have to allocate a new area in the bin, and store an empty image in it. - // Add a 1px border around every image. - var rect = this.bin.allocate(packWidth, packHeight); - if (rect.x < 0) { - console.warn('SpriteAtlas out of space.'); - return rect; +LineAtlas.prototype.setSprite = function (sprite) { + this.sprite = sprite; +}; +LineAtlas.prototype.getDash = function (dasharray, round) { + var key = dasharray.join(',') + round; + if (!this.positions[key]) { + this.positions[key] = this.addDash(dasharray, round); } - - return rect; + return this.positions[key]; }; - -SpriteAtlas.prototype.getImage = function(name, wrap) { - if (this.images[name]) { - return this.images[name]; +LineAtlas.prototype.addDash = function (dasharray, round) { + var n = round ? 7 : 0; + var height = 2 * n + 1; + var offset = 128; + if (this.nextRow + height > this.height) { + util.warnOnce('LineAtlas out of space'); + return null; } - - if (!this.sprite) { - return null; - } - - var pos = this.sprite.getSpritePosition(name); - if (!pos.width || !pos.height) { - return null; - } - - var rect = this.allocateImage(pos.width, pos.height); - if (rect.x < 0) { - return rect; - } - - var image = new AtlasImage(rect, pos.width / pos.pixelRatio, pos.height / pos.pixelRatio, pos.sdf, pos.pixelRatio / this.pixelRatio); - this.images[name] = image; - - this.copy(rect, pos, wrap); - - return image; -}; - - -// Return position of a repeating fill pattern. -SpriteAtlas.prototype.getPosition = function(name, repeating) { - var image = this.getImage(name, repeating); - var rect = image && image.rect; - - if (!rect) { - return null; + var length = 0; + for (var i = 0; i < dasharray.length; i++) { + length += dasharray[i]; } - - var width = image.width * image.pixelRatio; - var height = image.height * image.pixelRatio; - var padding = 1; - - return { - size: [image.width, image.height], - tl: [(rect.x + padding) / this.width, (rect.y + padding) / this.height], - br: [(rect.x + padding + width) / this.width, (rect.y + padding + height) / this.height] - }; -}; - - -SpriteAtlas.prototype.allocate = function() { - if (!this.data) { - var w = Math.floor(this.width * this.pixelRatio); - var h = Math.floor(this.height * this.pixelRatio); - this.data = new Uint32Array(w * h); - for (var i = 0; i < this.data.length; i++) { - this.data[i] = 0; + var stretch = this.width / length; + var halfWidth = stretch / 2; + var oddLength = dasharray.length % 2 === 1; + for (var y = -n; y <= n; y++) { + var row = this.nextRow + n + y; + var index = this.width * row; + var left = oddLength ? -dasharray[dasharray.length - 1] : 0; + var right = dasharray[0]; + var partIndex = 1; + for (var x = 0; x < this.width; x++) { + while (right < x / stretch) { + left = right; + right = right + dasharray[partIndex]; + if (oddLength && partIndex === dasharray.length - 1) { + right += dasharray[0]; + } + partIndex++; + } + var distLeft = Math.abs(x - left * stretch); + var distRight = Math.abs(x - right * stretch); + var dist = Math.min(distLeft, distRight); + var inside = partIndex % 2 === 1; + var signedDistance; + if (round) { + var distMiddle = n ? y / n * (halfWidth + 1) : 0; + if (inside) { + var distEdge = halfWidth - Math.abs(distMiddle); + signedDistance = Math.sqrt(dist * dist + distEdge * distEdge); + } else { + signedDistance = halfWidth - Math.sqrt(dist * dist + distMiddle * distMiddle); + } + } else { + signedDistance = (inside ? 1 : -1) * dist; + } + this.data[3 + (index + x) * 4] = Math.max(0, Math.min(255, signedDistance + offset)); } } -}; - - -SpriteAtlas.prototype.copy = function(dst, src, wrap) { - if (!this.sprite.img.data) return; - var srcImg = new Uint32Array(this.sprite.img.data.buffer); - - this.allocate(); - var dstImg = this.data; - - var padding = 1; - - copyBitmap( - /* source buffer */ srcImg, - /* source stride */ this.sprite.img.width, - /* source x */ src.x, - /* source y */ src.y, - /* dest buffer */ dstImg, - /* dest stride */ this.width * this.pixelRatio, - /* dest x */ (dst.x + padding) * this.pixelRatio, - /* dest y */ (dst.y + padding) * this.pixelRatio, - /* icon dimension */ src.width, - /* icon dimension */ src.height, - /* wrap */ wrap - ); - + var pos = { + y: (this.nextRow + n + 0.5) / this.height, + height: 2 * n / this.height, + width: length + }; + this.nextRow += height; this.dirty = true; + return pos; }; - -SpriteAtlas.prototype.setSprite = function(sprite) { - if (sprite) { - this.pixelRatio = browser.devicePixelRatio > 1 ? 2 : 1; - - if (this.canvas) { - this.canvas.width = this.width * this.pixelRatio; - this.canvas.height = this.height * this.pixelRatio; - } - } - this.sprite = sprite; -}; - -SpriteAtlas.prototype.addIcons = function(icons, callback) { - for (var i = 0; i < icons.length; i++) { - this.getImage(icons[i]); - } - - callback(null, this.images); -}; - -SpriteAtlas.prototype.bind = function(gl, linear) { - var first = false; +LineAtlas.prototype.bind = function (gl) { if (!this.texture) { this.texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - first = true; + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.data); } else { gl.bindTexture(gl.TEXTURE_2D, this.texture); + if (this.dirty) { + this.dirty = false; + gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, this.width, this.height, gl.RGBA, gl.UNSIGNED_BYTE, this.data); + } } - - var filterVal = linear ? gl.LINEAR : gl.NEAREST; - if (filterVal !== this.filter) { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filterVal); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filterVal); - this.filter = filterVal; +}; +},{"../util/util":188}],99:[function(require,module,exports){ +'use strict'; +var browser = require('../util/browser'); +var mat4 = require('gl-matrix').mat4; +var FrameHistory = require('./frame_history'); +var SourceCache = require('../source/source_cache'); +var EXTENT = require('../data/bucket').EXTENT; +var pixelsToTileUnits = require('../source/pixels_to_tile_units'); +var util = require('../util/util'); +var StructArrayType = require('../util/struct_array'); +var Buffer = require('../data/buffer'); +var VertexArrayObject = require('./vertex_array_object'); +var RasterBoundsArray = require('./draw_raster').RasterBoundsArray; +var createUniformPragmas = require('./create_uniform_pragmas'); +module.exports = Painter; +function Painter(gl, transform) { + this.gl = gl; + this.transform = transform; + this.reusableTextures = {}; + this.preFbos = {}; + this.frameHistory = new FrameHistory(); + this.setup(); + this.numSublayers = SourceCache.maxUnderzooming + SourceCache.maxOverzooming + 1; + this.depthEpsilon = 1 / Math.pow(2, 16); + this.lineWidthRange = gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE); +} +util.extend(Painter.prototype, require('./painter/use_program')); +Painter.prototype.resize = function (width, height) { + var gl = this.gl; + this.width = width * browser.devicePixelRatio; + this.height = height * browser.devicePixelRatio; + gl.viewport(0, 0, this.width, this.height); +}; +Painter.prototype.setup = function () { + var gl = this.gl; + gl.verbose = true; + gl.enable(gl.BLEND); + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + gl.enable(gl.STENCIL_TEST); + gl.enable(gl.DEPTH_TEST); + gl.depthFunc(gl.LEQUAL); + this._depthMask = false; + gl.depthMask(false); + var PosArray = this.PosArray = new StructArrayType({ + members: [{ + name: 'a_pos', + type: 'Int16', + components: 2 + }] + }); + var tileExtentArray = new PosArray(); + tileExtentArray.emplaceBack(0, 0); + tileExtentArray.emplaceBack(EXTENT, 0); + tileExtentArray.emplaceBack(0, EXTENT); + tileExtentArray.emplaceBack(EXTENT, EXTENT); + this.tileExtentBuffer = new Buffer(tileExtentArray.serialize(), PosArray.serialize(), Buffer.BufferType.VERTEX); + this.tileExtentVAO = new VertexArrayObject(); + this.tileExtentPatternVAO = new VertexArrayObject(); + var debugArray = new PosArray(); + debugArray.emplaceBack(0, 0); + debugArray.emplaceBack(EXTENT, 0); + debugArray.emplaceBack(EXTENT, EXTENT); + debugArray.emplaceBack(0, EXTENT); + debugArray.emplaceBack(0, 0); + this.debugBuffer = new Buffer(debugArray.serialize(), PosArray.serialize(), Buffer.BufferType.VERTEX); + this.debugVAO = new VertexArrayObject(); + var rasterBoundsArray = new RasterBoundsArray(); + rasterBoundsArray.emplaceBack(0, 0, 0, 0); + rasterBoundsArray.emplaceBack(EXTENT, 0, 32767, 0); + rasterBoundsArray.emplaceBack(0, EXTENT, 0, 32767); + rasterBoundsArray.emplaceBack(EXTENT, EXTENT, 32767, 32767); + this.rasterBoundsBuffer = new Buffer(rasterBoundsArray.serialize(), RasterBoundsArray.serialize(), Buffer.BufferType.VERTEX); + this.rasterBoundsVAO = new VertexArrayObject(); +}; +Painter.prototype.clearColor = function () { + var gl = this.gl; + gl.clearColor(0, 0, 0, 0); + gl.clear(gl.COLOR_BUFFER_BIT); +}; +Painter.prototype.clearStencil = function () { + var gl = this.gl; + gl.clearStencil(0); + gl.stencilMask(255); + gl.clear(gl.STENCIL_BUFFER_BIT); +}; +Painter.prototype.clearDepth = function () { + var gl = this.gl; + gl.clearDepth(1); + this.depthMask(true); + gl.clear(gl.DEPTH_BUFFER_BIT); +}; +Painter.prototype._renderTileClippingMasks = function (coords) { + var gl = this.gl; + gl.colorMask(false, false, false, false); + this.depthMask(false); + gl.disable(gl.DEPTH_TEST); + gl.enable(gl.STENCIL_TEST); + gl.stencilMask(248); + gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE); + var idNext = 1; + this._tileClippingMaskIDs = {}; + for (var i = 0; i < coords.length; i++) { + var coord = coords[i]; + var id = this._tileClippingMaskIDs[coord.id] = idNext++ << 3; + gl.stencilFunc(gl.ALWAYS, id, 248); + var pragmas = createUniformPragmas([ + { + name: 'u_color', + components: 4 + }, + { + name: 'u_opacity', + components: 1 + } + ]); + var program = this.useProgram('fill', [], pragmas, pragmas); + gl.uniformMatrix4fv(program.u_matrix, false, coord.posMatrix); + this.tileExtentVAO.bind(gl, program, this.tileExtentBuffer); + gl.drawArrays(gl.TRIANGLE_STRIP, 0, this.tileExtentBuffer.length); } - - if (this.dirty) { - this.allocate(); - - if (first) { - gl.texImage2D( - gl.TEXTURE_2D, // enum target - 0, // ind level - gl.RGBA, // ind internalformat - this.width * this.pixelRatio, // GLsizei width - this.height * this.pixelRatio, // GLsizei height - 0, // ind border - gl.RGBA, // enum format - gl.UNSIGNED_BYTE, // enum type - new Uint8Array(this.data.buffer) // Object data - ); - } else { - gl.texSubImage2D( - gl.TEXTURE_2D, // enum target - 0, // int level - 0, // int xoffset - 0, // int yoffset - this.width * this.pixelRatio, // long width - this.height * this.pixelRatio, // long height - gl.RGBA, // enum format - gl.UNSIGNED_BYTE, // enum type - new Uint8Array(this.data.buffer) // Object pixels - ); + gl.stencilMask(0); + gl.colorMask(true, true, true, true); + this.depthMask(true); + gl.enable(gl.DEPTH_TEST); +}; +Painter.prototype.enableTileClippingMask = function (coord) { + var gl = this.gl; + gl.stencilFunc(gl.EQUAL, this._tileClippingMaskIDs[coord.id], 248); +}; +Painter.prototype.prepareBuffers = function () { +}; +Painter.prototype.bindDefaultFramebuffer = function () { + var gl = this.gl; + gl.bindFramebuffer(gl.FRAMEBUFFER, null); +}; +var draw = { + symbol: require('./draw_symbol'), + circle: require('./draw_circle'), + line: require('./draw_line'), + fill: require('./draw_fill'), + raster: require('./draw_raster'), + background: require('./draw_background'), + debug: require('./draw_debug') +}; +Painter.prototype.render = function (style, options) { + this.style = style; + this.options = options; + this.lineAtlas = style.lineAtlas; + this.spriteAtlas = style.spriteAtlas; + this.spriteAtlas.setSprite(style.sprite); + this.glyphSource = style.glyphSource; + this.frameHistory.record(this.transform.zoom); + this.prepareBuffers(); + this.clearColor(); + this.clearDepth(); + this.showOverdrawInspector(options.showOverdrawInspector); + this.depthRange = (style._order.length + 2) * this.numSublayers * this.depthEpsilon; + this.renderPass({ isOpaquePass: true }); + this.renderPass({ isOpaquePass: false }); +}; +Painter.prototype.renderPass = function (options) { + var groups = this.style._groups; + var isOpaquePass = options.isOpaquePass; + this.currentLayer = isOpaquePass ? this.style._order.length : -1; + for (var i = 0; i < groups.length; i++) { + var group = groups[isOpaquePass ? groups.length - 1 - i : i]; + var sourceCache = this.style.sourceCaches[group.source]; + var j; + var coords = []; + if (sourceCache) { + coords = sourceCache.getVisibleCoordinates(); + for (j = 0; j < coords.length; j++) { + coords[j].posMatrix = this.transform.calculatePosMatrix(coords[j], sourceCache.getSource().maxzoom); + } + this.clearStencil(); + if (sourceCache.prepare) + sourceCache.prepare(); + if (sourceCache.getSource().isTileClipped) { + this._renderTileClippingMasks(coords); + } } - - this.dirty = false; - - // DEBUG - if (this.ctx) { - var data = this.ctx.getImageData(0, 0, this.width * this.pixelRatio, this.height * this.pixelRatio); - data.data.set(new Uint8ClampedArray(this.data.buffer)); - this.ctx.putImageData(data, 0, 0); - - this.ctx.strokeStyle = 'red'; - for (var k = 0; k < this.bin.free.length; k++) { - var free = this.bin.free[k]; - this.ctx.strokeRect(free.x * this.pixelRatio, free.y * this.pixelRatio, free.w * this.pixelRatio, free.h * this.pixelRatio); + if (isOpaquePass) { + if (!this._showOverdrawInspector) { + this.gl.disable(this.gl.BLEND); } + this.isOpaquePass = true; + } else { + this.gl.enable(this.gl.BLEND); + this.isOpaquePass = false; + coords.reverse(); + } + for (j = 0; j < group.length; j++) { + var layer = group[isOpaquePass ? group.length - 1 - j : j]; + this.currentLayer += isOpaquePass ? -1 : 1; + this.renderLayer(this, sourceCache, layer, coords); + } + if (sourceCache) { + draw.debug(this, sourceCache, coords); } - // END DEBUG } }; - -function AtlasImage(rect, width, height, sdf, pixelRatio) { - this.rect = rect; - this.width = width; - this.height = height; - this.sdf = sdf; - this.pixelRatio = pixelRatio; +Painter.prototype.depthMask = function (mask) { + if (mask !== this._depthMask) { + this._depthMask = mask; + this.gl.depthMask(mask); + } +}; +Painter.prototype.renderLayer = function (painter, sourceCache, layer, coords) { + if (layer.isHidden(this.transform.zoom)) + return; + if (layer.type !== 'background' && !coords.length) + return; + this.id = layer.id; + draw[layer.type](painter, sourceCache, layer, coords); +}; +Painter.prototype.setDepthSublayer = function (n) { + var farDepth = 1 - ((1 + this.currentLayer) * this.numSublayers + n) * this.depthEpsilon; + var nearDepth = farDepth - 1 + this.depthRange; + this.gl.depthRange(nearDepth, farDepth); +}; +Painter.prototype.translatePosMatrix = function (matrix, tile, translate, anchor) { + if (!translate[0] && !translate[1]) + return matrix; + if (anchor === 'viewport') { + var sinA = Math.sin(-this.transform.angle); + var cosA = Math.cos(-this.transform.angle); + translate = [ + translate[0] * cosA - translate[1] * sinA, + translate[0] * sinA + translate[1] * cosA + ]; + } + var translation = [ + pixelsToTileUnits(tile, translate[0], this.transform.zoom), + pixelsToTileUnits(tile, translate[1], this.transform.zoom), + 0 + ]; + var translatedMatrix = new Float32Array(16); + mat4.translate(translatedMatrix, matrix, translation); + return translatedMatrix; +}; +Painter.prototype.saveTexture = function (texture) { + var textures = this.reusableTextures[texture.size]; + if (!textures) { + this.reusableTextures[texture.size] = [texture]; + } else { + textures.push(texture); + } +}; +Painter.prototype.getTexture = function (size) { + var textures = this.reusableTextures[size]; + return textures && textures.length > 0 ? textures.pop() : null; +}; +Painter.prototype.lineWidth = function (width) { + this.gl.lineWidth(util.clamp(width, this.lineWidthRange[0], this.lineWidthRange[1])); +}; +Painter.prototype.showOverdrawInspector = function (enabled) { + if (!enabled && !this._showOverdrawInspector) + return; + this._showOverdrawInspector = enabled; + var gl = this.gl; + if (enabled) { + gl.blendFunc(gl.CONSTANT_COLOR, gl.ONE); + var numOverdrawSteps = 8; + var a = 1 / numOverdrawSteps; + gl.blendColor(a, a, a, 0); + gl.clearColor(0, 0, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + } else { + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + } +}; +},{"../data/bucket":72,"../data/buffer":77,"../source/pixels_to_tile_units":107,"../source/source_cache":111,"../util/browser":171,"../util/struct_array":186,"../util/util":188,"./create_uniform_pragmas":88,"./draw_background":89,"./draw_circle":90,"./draw_debug":92,"./draw_fill":93,"./draw_line":94,"./draw_raster":95,"./draw_symbol":96,"./frame_history":97,"./painter/use_program":100,"./vertex_array_object":101,"gl-matrix":29}],100:[function(require,module,exports){ +'use strict'; +var util = require('../../util/util'); +var shaders = require('mapbox-gl-shaders'); +var utilSource = shaders.util; +module.exports._createProgram = function (name, defines, vertexPragmas, fragmentPragmas) { + var gl = this.gl; + var program = gl.createProgram(); + var definition = shaders[name]; + var definesSource = '#define MAPBOX_GL_JS;\n'; + for (var j = 0; j < defines.length; j++) { + definesSource += '#define ' + defines[j] + ';\n'; + } + var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); + gl.shaderSource(fragmentShader, applyPragmas(definesSource + definition.fragmentSource, fragmentPragmas)); + gl.compileShader(fragmentShader); + gl.attachShader(program, fragmentShader); + var vertexShader = gl.createShader(gl.VERTEX_SHADER); + gl.shaderSource(vertexShader, applyPragmas(definesSource + utilSource + definition.vertexSource, vertexPragmas)); + gl.compileShader(vertexShader); + gl.attachShader(program, vertexShader); + gl.linkProgram(program); + var attributes = {}; + var numAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES); + for (var i = 0; i < numAttributes; i++) { + var attribute = gl.getActiveAttrib(program, i); + attributes[attribute.name] = gl.getAttribLocation(program, attribute.name); + } + var uniforms = {}; + var numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); + for (var ui = 0; ui < numUniforms; ui++) { + var uniform = gl.getActiveUniform(program, ui); + uniforms[uniform.name] = gl.getUniformLocation(program, uniform.name); + } + return util.extend({ + program: program, + definition: definition, + attributes: attributes, + numAttributes: numAttributes + }, attributes, uniforms); +}; +module.exports._createProgramCached = function (name, defines, vertexPragmas, fragmentPragmas) { + this.cache = this.cache || {}; + var key = JSON.stringify({ + name: name, + defines: defines, + vertexPragmas: vertexPragmas, + fragmentPragmas: fragmentPragmas + }); + if (!this.cache[key]) { + this.cache[key] = this._createProgram(name, defines, vertexPragmas, fragmentPragmas); + } + return this.cache[key]; +}; +module.exports.useProgram = function (nextProgramName, defines, vertexPragmas, fragmentPragmas) { + var gl = this.gl; + defines = defines || []; + if (this._showOverdrawInspector) { + defines = defines.concat('OVERDRAW_INSPECTOR'); + } + var nextProgram = this._createProgramCached(nextProgramName, defines, vertexPragmas, fragmentPragmas); + var previousProgram = this.currentProgram; + if (previousProgram !== nextProgram) { + gl.useProgram(nextProgram.program); + this.currentProgram = nextProgram; + } + return nextProgram; +}; +function applyPragmas(source, pragmas) { + return source.replace(/#pragma mapbox: ([\w]+) ([\w]+) ([\w]+) ([\w]+)/g, function (match, operation, precision, type, name) { + return pragmas[operation][name].replace(/{type}/g, type).replace(/{precision}/g, precision); + }); } - -},{"../util/browser":102,"shelf-pack":165}],85:[function(require,module,exports){ +},{"../../util/util":188,"mapbox-gl-shaders":46}],101:[function(require,module,exports){ 'use strict'; - +module.exports = VertexArrayObject; +function VertexArrayObject() { + this.boundProgram = null; + this.boundVertexBuffer = null; + this.boundVertexBuffer2 = null; + this.boundElementBuffer = null; + this.vao = null; +} +VertexArrayObject.prototype.bind = function (gl, program, layoutVertexBuffer, elementBuffer, vertexBuffer2) { + if (gl.extVertexArrayObject === undefined) { + gl.extVertexArrayObject = gl.getExtension('OES_vertex_array_object'); + } + var isFreshBindRequired = !this.vao || this.boundProgram !== program || this.boundVertexBuffer !== layoutVertexBuffer || this.boundVertexBuffer2 !== vertexBuffer2 || this.boundElementBuffer !== elementBuffer; + if (!gl.extVertexArrayObject || isFreshBindRequired) { + this.freshBind(gl, program, layoutVertexBuffer, elementBuffer, vertexBuffer2); + } else { + gl.extVertexArrayObject.bindVertexArrayOES(this.vao); + } +}; +VertexArrayObject.prototype.freshBind = function (gl, program, layoutVertexBuffer, elementBuffer, vertexBuffer2) { + var numPrevAttributes; + var numNextAttributes = program.numAttributes; + if (gl.extVertexArrayObject) { + if (this.vao) + this.destroy(gl); + this.vao = gl.extVertexArrayObject.createVertexArrayOES(); + gl.extVertexArrayObject.bindVertexArrayOES(this.vao); + numPrevAttributes = 0; + this.boundProgram = program; + this.boundVertexBuffer = layoutVertexBuffer; + this.boundVertexBuffer2 = vertexBuffer2; + this.boundElementBuffer = elementBuffer; + } else { + numPrevAttributes = gl.currentNumAttributes || 0; + for (var i = numNextAttributes; i < numPrevAttributes; i++) { + gl.disableVertexAttribArray(i); + } + } + for (var j = numPrevAttributes; j < numNextAttributes; j++) { + gl.enableVertexAttribArray(j); + } + layoutVertexBuffer.bind(gl); + layoutVertexBuffer.setVertexAttribPointers(gl, program); + if (vertexBuffer2) { + vertexBuffer2.bind(gl); + vertexBuffer2.setVertexAttribPointers(gl, program); + } + if (elementBuffer) { + elementBuffer.bind(gl); + } + gl.currentNumAttributes = numNextAttributes; +}; +VertexArrayObject.prototype.destroy = function (gl) { + var ext = gl.extVertexArrayObject; + if (ext && this.vao) { + ext.deleteVertexArrayOES(this.vao); + this.vao = null; + } +}; +},{}],102:[function(require,module,exports){ +'use strict'; +var Evented = require('../util/evented'); var util = require('../util/util'); -var interpolate = require('../util/interpolate'); -var browser = require('../util/browser'); -var LngLat = require('../geo/lng_lat'); -var LngLatBounds = require('../geo/lng_lat_bounds'); -var Point = require('point-geometry'); - -/** - * Options common to Map#jumpTo, Map#easeTo, and Map#flyTo, controlling the destination - * location, zoom level, bearing and pitch. All properties are options; unspecified - * options will default to the current value for that property. - * - * @typedef {Object} CameraOptions - * @property {LngLat} center Map center - * @property {number} zoom Map zoom level - * @property {number} bearing Map rotation bearing in degrees counter-clockwise from north - * @property {number} pitch Map angle in degrees at which the camera is looking at the ground - * @property {LngLat} around If zooming, the zoom center (defaults to map center) - */ - -/** - * Options common to map movement methods that involve animation, such as Map#panBy and - * Map#easeTo, controlling the duration of the animation and easing function. All properties - * are optional. - * - * @typedef {Object} AnimationOptions - * @property {number} duration Number in milliseconds - * @property {Function} easing - * @property {Array} offset point, origin of movement relative to map center - * @property {boolean} animate When set to false, no animation happens - */ - -var Camera = module.exports = function() {}; - -util.extend(Camera.prototype, /** @lends Map.prototype */{ - /** - * Get the current view geographical point. - * @returns {LngLat} - */ - getCenter: function() { return this.transform.center; }, - - /** - * Sets a map location. Equivalent to `jumpTo({center: center})`. - * - * @param {LngLat} center Map center to jump to - * @param {EventData} [eventData] Data to propagate to any event receivers - * @fires movestart - * @fires moveend - * @returns {Map} `this` - * @example - * map.setCenter([-74, 38]); - */ - setCenter: function(center, eventData) { - this.jumpTo({center: center}, eventData); - return this; - }, - - /** - * Pan by a certain number of pixels - * - * @param {Array} offset [x, y] - * @param {AnimationOptions} [options] - * @param {EventData} [eventData] Data to propagate to any event receivers - * @fires movestart - * @fires moveend - * @returns {Map} `this` - */ - panBy: function(offset, options, eventData) { - this.panTo(this.transform.center, - util.extend({offset: Point.convert(offset).mult(-1)}, options), eventData); - return this; - }, - - /** - * Pan to a certain location with easing - * - * @param {LngLat} lnglat Location to pan to - * @param {AnimationOptions} [options] - * @param {EventData} [eventData] Data to propagate to any event receivers - * @fires movestart - * @fires moveend - * @returns {Map} `this` - */ - panTo: function(lnglat, options, eventData) { - this.stop(); - - lnglat = LngLat.convert(lnglat); - - options = util.extend({ - duration: 500, - easing: util.ease, - offset: [0, 0] - }, options); - - var tr = this.transform, - offset = Point.convert(options.offset).rotate(-tr.angle), - from = tr.point, - to = tr.project(lnglat).sub(offset); - - if (!options.noMoveStart) { - this.fire('movestart', eventData); +var window = require('../util/window'); +var EXTENT = require('../data/bucket').EXTENT; +module.exports = GeoJSONSource; +function GeoJSONSource(id, options, dispatcher) { + options = options || {}; + this.id = id; + this.dispatcher = dispatcher; + this._data = options.data; + if (options.maxzoom !== undefined) + this.maxzoom = options.maxzoom; + if (options.type) + this.type = options.type; + var scale = EXTENT / this.tileSize; + this.workerOptions = util.extend({ + source: this.id, + cluster: options.cluster || false, + geojsonVtOptions: { + buffer: (options.buffer !== undefined ? options.buffer : 128) * scale, + tolerance: (options.tolerance !== undefined ? options.tolerance : 0.375) * scale, + extent: EXTENT, + maxZoom: this.maxzoom + }, + superclusterOptions: { + maxZoom: Math.min(options.clusterMaxZoom, this.maxzoom - 1) || this.maxzoom - 1, + extent: EXTENT, + radius: (options.clusterRadius || 50) * scale, + log: false + } + }, options.workerOptions); + this._updateWorkerData(function done(err) { + if (err) { + this.fire('error', { error: err }); + return; } - - this._ease(function(k) { - tr.center = tr.unproject(from.add(to.sub(from).mult(k))); - this.fire('move', eventData); - }, function() { - this.fire('moveend', eventData); - }, options); - - return this; + this.fire('data', { dataType: 'source' }); + this.fire('source.load'); + }.bind(this)); +} +GeoJSONSource.prototype = util.inherit(Evented, { + type: 'geojson', + minzoom: 0, + maxzoom: 18, + tileSize: 512, + isTileClipped: true, + reparseOverscaled: true, + onAdd: function (map) { + this.map = map; }, - - - /** - * Get the current zoom - * @returns {number} - */ - getZoom: function() { return this.transform.zoom; }, - - /** - * Sets a map zoom. Equivalent to `jumpTo({zoom: zoom})`. - * - * @param {number} zoom Map zoom level - * @param {EventData} [eventData] Data to propagate to any event receivers - * @fires movestart - * @fires zoomstart - * @fires move - * @fires zoom - * @fires moveend - * @fires zoomend - * @returns {Map} `this` - * @example - * // zoom the map to 5 - * map.setZoom(5); - */ - setZoom: function(zoom, eventData) { - this.jumpTo({zoom: zoom}, eventData); + setData: function (data) { + this._data = data; + this._updateWorkerData(function (err) { + if (err) { + return this.fire('error', { error: err }); + } + this.fire('data', { dataType: 'source' }); + }.bind(this)); return this; }, - - /** - * Zooms to a certain zoom level with easing. - * - * @param {number} zoom - * @param {AnimationOptions} [options] - * @param {EventData} [eventData] Data to propagate to any event receivers - * @fires movestart - * @fires zoomstart - * @fires move - * @fires zoom - * @fires moveend - * @fires zoomend - * @returns {Map} `this` - */ - zoomTo: function(zoom, options, eventData) { - this.stop(); - - options = util.extend({ - duration: 500 - }, options); - - options.easing = this._updateEasing(options.duration, zoom, options.easing); - - var tr = this.transform, - around = tr.center, - startZoom = tr.zoom; - - if (options.around) { - around = LngLat.convert(options.around); - } else if (options.offset) { - around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset))); - } - - if (options.animate === false) options.duration = 0; - - if (!this.zooming) { - this.zooming = true; - this.fire('movestart', eventData) - .fire('zoomstart', eventData); + _updateWorkerData: function (callback) { + var options = util.extend({}, this.workerOptions); + var data = this._data; + if (typeof data === 'string') { + options.url = resolveURL(data); + } else { + options.data = JSON.stringify(data); } - - this._ease(function(k) { - tr.setZoomAround(interpolate(startZoom, zoom, k), around); - this.fire('move', eventData) - .fire('zoom', eventData); - }, function() { - this.ease = null; - if (options.duration >= 200) { - this.zooming = false; - this.fire('moveend', eventData) - .fire('zoomend', eventData); + this.workerID = this.dispatcher.send(this.type + '.loadData', options, function (err) { + this._loaded = true; + callback(err); + }.bind(this)); + }, + loadTile: function (tile, callback) { + var overscaling = tile.coord.z > this.maxzoom ? Math.pow(2, tile.coord.z - this.maxzoom) : 1; + var params = { + type: this.type, + uid: tile.uid, + coord: tile.coord, + zoom: tile.coord.z, + maxZoom: this.maxzoom, + tileSize: this.tileSize, + source: this.id, + overscaling: overscaling, + angle: this.map.transform.angle, + pitch: this.map.transform.pitch, + showCollisionBoxes: this.map.showCollisionBoxes + }; + tile.workerID = this.dispatcher.send('load tile', params, function (err, data) { + tile.unloadVectorData(this.map.painter); + if (tile.aborted) + return; + if (err) { + return callback(err); } - }, options); - - if (options.duration < 200) { - clearTimeout(this._onZoomEnd); - this._onZoomEnd = setTimeout(function() { - this.zooming = false; - this.fire('moveend', eventData) - .fire('zoomend', eventData); - }.bind(this), 200); - } - - return this; + tile.loadVectorData(data, this.map.painter); + if (tile.redoWhenDone) { + tile.redoWhenDone = false; + tile.redoPlacement(this); + } + return callback(null); + }.bind(this), this.workerID); }, - - /** - * Zoom in by 1 level - * - * @param {AnimationOptions} [options] - * @param {EventData} [eventData] Data to propagate to any event receivers - * @fires movestart - * @fires zoomstart - * @fires move - * @fires zoom - * @fires moveend - * @fires zoomend - * @returns {Map} `this` - */ - zoomIn: function(options, eventData) { - this.zoomTo(this.getZoom() + 1, options, eventData); - return this; + abortTile: function (tile) { + tile.aborted = true; }, - - /** - * Zoom out by 1 level - * - * @param {AnimationOptions} [options] - * @param {EventData} [eventData] Data to propagate to any event receivers - * @fires movestart - * @fires zoomstart - * @fires move - * @fires zoom - * @fires moveend - * @fires zoomend - * @returns {Map} `this` - */ - zoomOut: function(options, eventData) { - this.zoomTo(this.getZoom() - 1, options, eventData); - return this; + unloadTile: function (tile) { + tile.unloadVectorData(this.map.painter); + this.dispatcher.send('remove tile', { + uid: tile.uid, + source: this.id + }, function () { + }, tile.workerID); }, - - - /** - * Get the current bearing in degrees - * @returns {number} - */ - getBearing: function() { return this.transform.bearing; }, - - /** - * Sets a map rotation. Equivalent to `jumpTo({bearing: bearing})`. - * - * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north - * @param {EventData} [eventData] Data to propagate to any event receivers - * @fires movestart - * @fires moveend - * @returns {Map} `this` - * @example - * // rotate the map to 90 degrees - * map.setBearing(90); - */ - setBearing: function(bearing, eventData) { - this.jumpTo({bearing: bearing}, eventData); - return this; + serialize: function () { + return { + type: this.type, + data: this._data + }; + } +}); +function resolveURL(url) { + var a = window.document.createElement('a'); + a.href = url; + return a.href; +} +},{"../data/bucket":72,"../util/evented":179,"../util/util":188,"../util/window":173}],103:[function(require,module,exports){ +'use strict'; +var util = require('../util/util'); +var ajax = require('../util/ajax'); +var rewind = require('geojson-rewind'); +var GeoJSONWrapper = require('./geojson_wrapper'); +var vtpbf = require('vt-pbf'); +var supercluster = require('supercluster'); +var geojsonvt = require('geojson-vt'); +var VectorTileWorkerSource = require('./vector_tile_worker_source'); +module.exports = GeoJSONWorkerSource; +function GeoJSONWorkerSource(actor, styleLayers, loadGeoJSON) { + if (loadGeoJSON) { + this.loadGeoJSON = loadGeoJSON; + } + VectorTileWorkerSource.call(this, actor, styleLayers); +} +GeoJSONWorkerSource.prototype = util.inherit(VectorTileWorkerSource, { + _geoJSONIndexes: {}, + loadVectorData: function (params, callback) { + var source = params.source, coord = params.coord; + if (!this._geoJSONIndexes[source]) { + return callback(null, null); + } + var geoJSONTile = this._geoJSONIndexes[source].getTile(Math.min(coord.z, params.maxZoom), coord.x, coord.y); + if (!geoJSONTile) { + return callback(null, null); + } + var geojsonWrapper = new GeoJSONWrapper(geoJSONTile.features); + geojsonWrapper.name = '_geojsonTileLayer'; + var pbf = vtpbf({ layers: { '_geojsonTileLayer': geojsonWrapper } }); + if (pbf.byteOffset !== 0 || pbf.byteLength !== pbf.buffer.byteLength) { + pbf = new Uint8Array(pbf); + } + geojsonWrapper.rawData = pbf.buffer; + callback(null, geojsonWrapper); + }, + loadData: function (params, callback) { + var handleData = function (err, data) { + if (err) + return callback(err); + if (typeof data != 'object') { + return callback(new Error('Input data is not a valid GeoJSON object.')); + } + rewind(data, true); + this._indexData(data, params, function (err, indexed) { + if (err) { + return callback(err); + } + this._geoJSONIndexes[params.source] = indexed; + callback(null); + }.bind(this)); + }.bind(this); + this.loadGeoJSON(params, handleData); }, - - /** - * Rotate bearing by a certain number of degrees with easing - * - * @param {number} bearing - * @param {AnimationOptions} [options] - * @param {EventData} [eventData] Data to propagate to any event receivers - * @fires movestart - * @fires moveend - * @returns {Map} `this` - */ - rotateTo: function(bearing, options, eventData) { - this.stop(); - - options = util.extend({ - duration: 500, - easing: util.ease - }, options); - - var tr = this.transform, - start = this.getBearing(), - around = tr.center; - - if (options.around) { - around = LngLat.convert(options.around); - } else if (options.offset) { - around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset))); - } - - bearing = this._normalizeBearing(bearing, start); - - this.rotating = true; - if (!options.noMoveStart) { - this.fire('movestart', eventData); + loadGeoJSON: function (params, callback) { + if (params.url) { + ajax.getJSON(params.url, callback); + } else if (typeof params.data === 'string') { + try { + return callback(null, JSON.parse(params.data)); + } catch (e) { + return callback(new Error('Input data is not a valid GeoJSON object.')); + } + } else { + return callback(new Error('Input data is not a valid GeoJSON object.')); } - - this._ease(function(k) { - tr.setBearingAround(interpolate(start, bearing, k), around); - this.fire('move', eventData) - .fire('rotate', eventData); - }, function() { - this.rotating = false; - this.fire('moveend', eventData); - }, options); - - return this; - }, - - /** - * Sets map bearing to 0 (north) with easing - * - * @param {AnimationOptions} [options] - * @param {EventData} [eventData] Data to propagate to any event receivers - * @fires movestart - * @fires moveend - * @returns {Map} `this` - */ - resetNorth: function(options, eventData) { - this.rotateTo(0, util.extend({duration: 1000}, options), eventData); - return this; }, - - /** - * Animates map bearing to 0 (north) if it's already close to it. - * - * @param {AnimationOptions} [options] - * @param {EventData} [eventData] Data to propagate to any event receivers - * @fires movestart - * @fires moveend - * @returns {Map} `this` - */ - snapToNorth: function(options, eventData) { - if (Math.abs(this.getBearing()) < this.options.bearingSnap) { - return this.resetNorth(options, eventData); + _indexData: function (data, params, callback) { + try { + if (params.cluster) { + callback(null, supercluster(params.superclusterOptions).load(data.features)); + } else { + callback(null, geojsonvt(data, params.geojsonVtOptions)); + } + } catch (err) { + return callback(err); } - return this; - }, - - /** - * Get the current angle in degrees - * @returns {number} - */ - getPitch: function() { return this.transform.pitch; }, - - /** - * Sets a map angle. Equivalent to `jumpTo({pitch: pitch})`. - * - * @param {number} pitch The angle at which the camera is looking at the ground - * @param {EventData} [eventData] Data to propagate to any event receivers - * @fires movestart - * @fires moveend - * @returns {Map} `this` - */ - setPitch: function(pitch, eventData) { - this.jumpTo({pitch: pitch}, eventData); - return this; - }, - - - /** - * Zoom to contain certain geographical bounds - * - * @param {LngLatBounds|Array>} bounds [[minLng, minLat], [maxLng, maxLat]] - * @param {Object} options - * @param {boolean} [options.linear] When true, the map transitions to the new camera using - * {@link #Map.easeTo}. When false, the map transitions using {@link #Map.flyTo}. See - * {@link #Map.flyTo} for information on options specific to that animation transition. - * @param {Function} options.easing - * @param {number} options.padding how much padding there is around the given bounds on each side in pixels - * @param {number} options.maxZoom The resulting zoom level will be at most - * this value. - * @param {EventData} [eventData] Data to propagate to any event receivers - * @fires movestart - * @fires moveend - * @returns {Map} `this` - */ - fitBounds: function(bounds, options, eventData) { - - options = util.extend({ - padding: 0, - offset: [0, 0], - maxZoom: Infinity - }, options); - - bounds = LngLatBounds.convert(bounds); - - var offset = Point.convert(options.offset), - tr = this.transform, - nw = tr.project(bounds.getNorthWest()), - se = tr.project(bounds.getSouthEast()), - size = se.sub(nw), - scaleX = (tr.width - options.padding * 2 - Math.abs(offset.x) * 2) / size.x, - scaleY = (tr.height - options.padding * 2 - Math.abs(offset.y) * 2) / size.y; - - options.center = tr.unproject(nw.add(se).div(2)); - options.zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom); - options.bearing = 0; - - return options.linear ? - this.easeTo(options, eventData) : - this.flyTo(options, eventData); - }, - - /** - * Change any combination of center, zoom, bearing, and pitch, without - * a transition. The map will retain the current values for any options - * not included in `options`. - * - * @param {CameraOptions} options map view options - * @param {EventData} [eventData] Data to propagate to any event receivers - * @fires movestart - * @fires zoomstart - * @fires move - * @fires zoom - * @fires rotate - * @fires pitch - * @fires zoomend - * @fires moveend - * @returns {Map} `this` - */ - jumpTo: function(options, eventData) { - this.stop(); - - var tr = this.transform, - zoomChanged = false, - bearingChanged = false, - pitchChanged = false; - - if ('zoom' in options && tr.zoom !== +options.zoom) { - zoomChanged = true; - tr.zoom = +options.zoom; + } +}); +},{"../util/ajax":170,"../util/util":188,"./geojson_wrapper":104,"./vector_tile_worker_source":115,"geojson-rewind":17,"geojson-vt":21,"supercluster":204,"vt-pbf":216}],104:[function(require,module,exports){ +'use strict'; +var Point = require('point-geometry'); +var VectorTileFeature = require('vector-tile').VectorTileFeature; +var EXTENT = require('../data/bucket').EXTENT; +module.exports = GeoJSONWrapper; +function GeoJSONWrapper(features) { + this.features = features; + this.length = features.length; + this.extent = EXTENT; +} +GeoJSONWrapper.prototype.feature = function (i) { + return new FeatureWrapper(this.features[i]); +}; +function FeatureWrapper(feature) { + this.type = feature.type; + if (feature.type === 1) { + this.rawGeometry = []; + for (var i = 0; i < feature.geometry.length; i++) { + this.rawGeometry.push([feature.geometry[i]]); } - - if ('center' in options) { - tr.center = LngLat.convert(options.center); + } else { + this.rawGeometry = feature.geometry; + } + this.properties = feature.tags; + this.extent = EXTENT; +} +FeatureWrapper.prototype.loadGeometry = function () { + var rings = this.rawGeometry; + this.geometry = []; + for (var i = 0; i < rings.length; i++) { + var ring = rings[i], newRing = []; + for (var j = 0; j < ring.length; j++) { + newRing.push(new Point(ring[j][0], ring[j][1])); } - - if ('bearing' in options && tr.bearing !== +options.bearing) { - bearingChanged = true; - tr.bearing = +options.bearing; + this.geometry.push(newRing); + } + return this.geometry; +}; +FeatureWrapper.prototype.bbox = function () { + if (!this.geometry) + this.loadGeometry(); + var rings = this.geometry, x1 = Infinity, x2 = -Infinity, y1 = Infinity, y2 = -Infinity; + for (var i = 0; i < rings.length; i++) { + var ring = rings[i]; + for (var j = 0; j < ring.length; j++) { + var coord = ring[j]; + x1 = Math.min(x1, coord.x); + x2 = Math.max(x2, coord.x); + y1 = Math.min(y1, coord.y); + y2 = Math.max(y2, coord.y); } - - if ('pitch' in options && tr.pitch !== +options.pitch) { - pitchChanged = true; - tr.pitch = +options.pitch; + } + return [ + x1, + y1, + x2, + y2 + ]; +}; +FeatureWrapper.prototype.toGeoJSON = VectorTileFeature.prototype.toGeoJSON; +},{"../data/bucket":72,"point-geometry":196,"vector-tile":212}],105:[function(require,module,exports){ +'use strict'; +var util = require('../util/util'); +var TileCoord = require('./tile_coord'); +var LngLat = require('../geo/lng_lat'); +var Point = require('point-geometry'); +var Evented = require('../util/evented'); +var ajax = require('../util/ajax'); +var EXTENT = require('../data/bucket').EXTENT; +var RasterBoundsArray = require('../render/draw_raster').RasterBoundsArray; +var Buffer = require('../data/buffer'); +var VertexArrayObject = require('../render/vertex_array_object'); +module.exports = ImageSource; +function ImageSource(id, options, dispatcher) { + this.id = id; + this.dispatcher = dispatcher; + this.url = options.url; + this.coordinates = options.coordinates; + ajax.getImage(options.url, function (err, image) { + if (err) + return this.fire('error', { error: err }); + this.image = image; + this._loaded = true; + this.fire('data', { dataType: 'source' }); + this.fire('source.load'); + if (this.map) { + this.setCoordinates(options.coordinates); } - - this.fire('movestart', eventData) - .fire('move', eventData); - - if (zoomChanged) { - this.fire('zoomstart', eventData) - .fire('zoom', eventData) - .fire('zoomend', eventData); + }.bind(this)); +} +ImageSource.prototype = util.inherit(Evented, { + minzoom: 0, + maxzoom: 22, + tileSize: 512, + onAdd: function (map) { + this.map = map; + if (this.image) { + this.setCoordinates(this.coordinates); } - - if (bearingChanged) { - this.fire('rotate', eventData); + }, + setCoordinates: function (coordinates) { + this.coordinates = coordinates; + var map = this.map; + var cornerZ0Coords = coordinates.map(function (coord) { + return map.transform.locationCoordinate(LngLat.convert(coord)).zoomTo(0); + }); + var centerCoord = this.centerCoord = util.getCoordinatesCenter(cornerZ0Coords); + centerCoord.column = Math.round(centerCoord.column); + centerCoord.row = Math.round(centerCoord.row); + this.minzoom = this.maxzoom = centerCoord.zoom; + this.coord = new TileCoord(centerCoord.zoom, centerCoord.column, centerCoord.row); + this._tileCoords = cornerZ0Coords.map(function (coord) { + var zoomedCoord = coord.zoomTo(centerCoord.zoom); + return new Point(Math.round((zoomedCoord.column - centerCoord.column) * EXTENT), Math.round((zoomedCoord.row - centerCoord.row) * EXTENT)); + }); + this.fire('data', { dataType: 'source' }); + return this; + }, + _setTile: function (tile) { + this._prepared = false; + this.tile = tile; + var maxInt16 = 32767; + var array = new RasterBoundsArray(); + array.emplaceBack(this._tileCoords[0].x, this._tileCoords[0].y, 0, 0); + array.emplaceBack(this._tileCoords[1].x, this._tileCoords[1].y, maxInt16, 0); + array.emplaceBack(this._tileCoords[3].x, this._tileCoords[3].y, 0, maxInt16); + array.emplaceBack(this._tileCoords[2].x, this._tileCoords[2].y, maxInt16, maxInt16); + this.tile.buckets = {}; + this.tile.boundsBuffer = new Buffer(array.serialize(), RasterBoundsArray.serialize(), Buffer.BufferType.VERTEX); + this.tile.boundsVAO = new VertexArrayObject(); + this.tile.state = 'loaded'; + }, + prepare: function () { + if (!this._loaded || !this.image || !this.image.complete) + return; + if (!this.tile) + return; + var painter = this.map.painter; + var gl = painter.gl; + if (!this._prepared) { + this.tile.texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this.tile.texture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.image); + } else { + gl.bindTexture(gl.TEXTURE_2D, this.tile.texture); + gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.image); } - - if (pitchChanged) { - this.fire('pitch', eventData); + }, + loadTile: function (tile, callback) { + if (this.coord && this.coord.toString() === tile.coord.toString()) { + this._setTile(tile); + callback(null); + } else { + tile.state = 'errored'; + callback(null); } - - return this.fire('moveend', eventData); }, - - /** - * Change any combination of center, zoom, bearing, and pitch, with a smooth animation - * between old and new values. The map will retain the current values for any options - * not included in `options`. - * - * @param {CameraOptions|AnimationOptions} options map view and animation options - * @param {EventData} [eventData] Data to propagate to any event receivers - * @fires movestart - * @fires zoomstart - * @fires move - * @fires zoom - * @fires rotate - * @fires pitch - * @fires zoomend - * @fires moveend - * @returns {Map} `this` - */ - easeTo: function(options, eventData) { - this.stop(); - - options = util.extend({ - offset: [0, 0], - duration: 500, - easing: util.ease - }, options); - - var tr = this.transform, - offset = Point.convert(options.offset).rotate(-tr.angle), - from = tr.point, - startWorldSize = tr.worldSize, - startZoom = this.getZoom(), - startBearing = this.getBearing(), - startPitch = this.getPitch(), - - zoom = 'zoom' in options ? +options.zoom : startZoom, - bearing = 'bearing' in options ? this._normalizeBearing(options.bearing, startBearing) : startBearing, - pitch = 'pitch' in options ? +options.pitch : startPitch, - - scale = tr.zoomScale(zoom - startZoom), - to = 'center' in options ? tr.project(LngLat.convert(options.center)).sub(offset.div(scale)) : from, - around = 'center' in options ? null : LngLat.convert(options.around); - - this.zooming = (zoom !== startZoom); - this.rotating = (startBearing !== bearing); - this.pitching = (pitch !== startPitch); - - this.fire('movestart', eventData); - if (this.zooming) { - this.fire('zoomstart', eventData); + serialize: function () { + return { + type: 'image', + urls: this.url, + coordinates: this.coordinates + }; + } +}); +},{"../data/bucket":72,"../data/buffer":77,"../geo/lng_lat":82,"../render/draw_raster":95,"../render/vertex_array_object":101,"../util/ajax":170,"../util/evented":179,"../util/util":188,"./tile_coord":113,"point-geometry":196}],106:[function(require,module,exports){ +'use strict'; +var util = require('../util/util'); +var ajax = require('../util/ajax'); +var browser = require('../util/browser'); +var normalizeURL = require('../util/mapbox').normalizeSourceURL; +module.exports = function (options, callback) { + var loaded = function (err, tileJSON) { + if (err) { + return callback(err); } - - this._ease(function (k) { - if (this.zooming && around) { - tr.setZoomAround(interpolate(startZoom, zoom, k), around); + var result = util.pick(tileJSON, [ + 'tiles', + 'minzoom', + 'maxzoom', + 'attribution' + ]); + if (tileJSON.vector_layers) { + result.vectorLayers = tileJSON.vector_layers; + result.vectorLayerIds = result.vectorLayers.map(function (layer) { + return layer.id; + }); + } + callback(null, result); + }; + if (options.url) { + ajax.getJSON(normalizeURL(options.url), loaded); + } else { + browser.frame(loaded.bind(null, null, options)); + } +}; +},{"../util/ajax":170,"../util/browser":171,"../util/mapbox":185,"../util/util":188}],107:[function(require,module,exports){ +'use strict'; +var Bucket = require('../data/bucket'); +module.exports = function (tile, pixelValue, z) { + return pixelValue * (Bucket.EXTENT / (tile.tileSize * Math.pow(2, z - tile.coord.z))); +}; +},{"../data/bucket":72}],108:[function(require,module,exports){ +'use strict'; +var TileCoord = require('./tile_coord'); +exports.rendered = function (sourceCache, styleLayers, queryGeometry, params, zoom, bearing) { + var tilesIn = sourceCache.tilesIn(queryGeometry); + tilesIn.sort(sortTilesIn); + var renderedFeatureLayers = []; + for (var r = 0; r < tilesIn.length; r++) { + var tileIn = tilesIn[r]; + if (!tileIn.tile.featureIndex) + continue; + renderedFeatureLayers.push(tileIn.tile.featureIndex.query({ + queryGeometry: tileIn.queryGeometry, + scale: tileIn.scale, + tileSize: tileIn.tile.tileSize, + bearing: bearing, + params: params + }, styleLayers)); + } + return mergeRenderedFeatureLayers(renderedFeatureLayers); +}; +exports.source = function (sourceCache, params) { + var tiles = sourceCache.getRenderableIds().map(function (id) { + return sourceCache.getTileByID(id); + }); + var result = []; + var dataTiles = {}; + for (var i = 0; i < tiles.length; i++) { + var tile = tiles[i]; + var dataID = new TileCoord(Math.min(tile.sourceMaxZoom, tile.coord.z), tile.coord.x, tile.coord.y, 0).id; + if (!dataTiles[dataID]) { + dataTiles[dataID] = true; + tile.querySourceFeatures(result, params); + } + } + return result; +}; +function sortTilesIn(a, b) { + var coordA = a.coord; + var coordB = b.coord; + return coordA.z - coordB.z || coordA.y - coordB.y || coordA.w - coordB.w || coordA.x - coordB.x; +} +function mergeRenderedFeatureLayers(tiles) { + var result = tiles[0] || {}; + for (var i = 1; i < tiles.length; i++) { + var tile = tiles[i]; + for (var layerID in tile) { + var tileFeatures = tile[layerID]; + var resultFeatures = result[layerID]; + if (resultFeatures === undefined) { + resultFeatures = result[layerID] = tileFeatures; } else { - if (this.zooming) tr.zoom = interpolate(startZoom, zoom, k); - tr.center = tr.unproject(from.add(to.sub(from).mult(k)), startWorldSize); - } - - if (this.rotating) { - tr.bearing = interpolate(startBearing, bearing, k); - } - - if (this.pitching) { - tr.pitch = interpolate(startPitch, pitch, k); - } - - this.fire('move', eventData); - if (this.zooming) { - this.fire('zoom', eventData); - } - if (this.rotating) { - this.fire('rotate', eventData); + for (var f = 0; f < tileFeatures.length; f++) { + resultFeatures.push(tileFeatures[f]); + } } - if (this.pitching) { - this.fire('pitch', eventData); + } + } + return result; +} +},{"./tile_coord":113}],109:[function(require,module,exports){ +'use strict'; +var util = require('../util/util'); +var ajax = require('../util/ajax'); +var Evented = require('../util/evented'); +var loadTileJSON = require('./load_tilejson'); +var normalizeURL = require('../util/mapbox').normalizeTileURL; +module.exports = RasterTileSource; +function RasterTileSource(id, options, dispatcher) { + this.id = id; + this.dispatcher = dispatcher; + util.extend(this, util.pick(options, [ + 'url', + 'scheme', + 'tileSize' + ])); + loadTileJSON(options, function (err, tileJSON) { + if (err) { + return this.fire('error', err); + } + util.extend(this, tileJSON); + this.fire('data', { dataType: 'source' }); + this.fire('source.load'); + }.bind(this)); +} +RasterTileSource.prototype = util.inherit(Evented, { + minzoom: 0, + maxzoom: 22, + roundZoom: true, + scheme: 'xyz', + tileSize: 512, + _loaded: false, + onAdd: function (map) { + this.map = map; + }, + serialize: function () { + return { + type: 'raster', + url: this.url, + tileSize: this.tileSize, + tiles: this.tiles + }; + }, + loadTile: function (tile, callback) { + var url = normalizeURL(tile.coord.url(this.tiles, null, this.scheme), this.url, this.tileSize); + tile.request = ajax.getImage(url, done.bind(this)); + function done(err, img) { + delete tile.request; + if (tile.aborted) + return; + if (err) { + return callback(err); } - }, function() { - if (this.zooming) { - this.fire('zoomend', eventData); + var gl = this.map.painter.gl; + tile.texture = this.map.painter.getTexture(img.width); + if (tile.texture) { + gl.bindTexture(gl.TEXTURE_2D, tile.texture); + gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, img); + } else { + tile.texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tile.texture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img); + tile.texture.size = img.width; } - this.fire('moveend', eventData); - - this.zooming = false; - this.rotating = false; - this.pitching = false; - }, options); - - return this; + gl.generateMipmap(gl.TEXTURE_2D); + this.map.animationLoop.set(this.map.style.rasterFadeDuration); + tile.state = 'loaded'; + callback(null); + } }, - - /** - * Change any combination of center, zoom, bearing, and pitch, animated along a curve that - * evokes flight. The transition animation seamlessly incorporates zooming and panning to help - * the user find his or her bearings even after traversing a great distance. - * - * @param {CameraOptions|AnimationOptions} options map view and animation options - * @param {number} [options.curve=1.42] Relative amount of zooming that takes place along the - * flight path. A high value maximizes zooming for an exaggerated animation, while a low - * value minimizes zooming for something closer to {@link #Map.easeTo}. 1.42 is the average - * value selected by participants in the user study in - * [van Wijk (2003)](https://www.win.tue.nl/~vanwijk/zoompan.pdf). A value of - * `Math.pow(6, 0.25)` would be equivalent to the root mean squared average velocity. A - * value of 1 would produce a circular motion. - * @param {number} [options.minZoom] Zero-based zoom level at the peak of the flight path. If - * `options.curve` is specified, this option is ignored. - * @param {number} [options.speed=1.2] Average speed of the animation. A speed of 1.2 means that - * the map appears to move along the flight path by 1.2 times `options.curve` screenfuls every - * second. A _screenful_ is the visible span in pixels. It does not correspond to a fixed - * physical distance but rather varies by zoom level. - * @param {number} [options.screenSpeed] Average speed of the animation, measured in screenfuls - * per second, assuming a linear timing curve. If `options.speed` is specified, this option - * is ignored. - * @param {Function} [options.easing] Transition timing curve - * @param {EventData} [eventData] Data to propagate to any event receivers - * @fires movestart - * @fires zoomstart - * @fires move - * @fires zoom - * @fires rotate - * @fires pitch - * @fires zoomend - * @fires moveend - * @returns {this} - * @example - * // fly with default options to null island - * map.flyTo({center: [0, 0], zoom: 9}); - * // using flyTo options - * map.flyTo({ - * center: [0, 0], - * zoom: 9, - * speed: 0.2, - * curve: 1, - * easing: function(t) { - * return t; - * } - * }); - */ - flyTo: function(options, eventData) { - // This method implements an “optimal path” animation, as detailed in: - // - // Van Wijk, Jarke J.; Nuij, Wim A. A. “Smooth and efficient zooming and panning.” INFOVIS - // ’03. pp. 15–22. . - // - // Where applicable, local variable documentation begins with the associated variable or - // function in van Wijk (2003). - - this.stop(); - - options = util.extend({ - offset: [0, 0], - speed: 1.2, - curve: 1.42, - easing: util.ease - }, options); - - var tr = this.transform, - offset = Point.convert(options.offset), - startZoom = this.getZoom(), - startBearing = this.getBearing(), - startPitch = this.getPitch(); - - var center = 'center' in options ? LngLat.convert(options.center) : this.getCenter(); - var zoom = 'zoom' in options ? +options.zoom : startZoom; - var bearing = 'bearing' in options ? this._normalizeBearing(options.bearing, startBearing) : startBearing; - var pitch = 'pitch' in options ? +options.pitch : startPitch; - - // If a path crossing the antimeridian would be shorter, extend the final coordinate so that - // interpolating between the two endpoints will cross it. - if (Math.abs(tr.center.lng) + Math.abs(center.lng) > 180) { - if (tr.center.lng > 0 && center.lng < 0) { - center.lng += 360; - } else if (tr.center.lng < 0 && center.lng > 0) { - center.lng -= 360; + abortTile: function (tile) { + if (tile.request) { + tile.request.abort(); + delete tile.request; + } + }, + unloadTile: function (tile) { + if (tile.texture) + this.map.painter.saveTexture(tile.texture); + } +}); +},{"../util/ajax":170,"../util/evented":179,"../util/mapbox":185,"../util/util":188,"./load_tilejson":106}],110:[function(require,module,exports){ +'use strict'; +var util = require('../util/util'); +var sourceTypes = { + 'vector': require('../source/vector_tile_source'), + 'raster': require('../source/raster_tile_source'), + 'geojson': require('../source/geojson_source'), + 'video': require('../source/video_source'), + 'image': require('../source/image_source') +}; +exports.create = function (id, source, dispatcher) { + source = new sourceTypes[source.type](id, source, dispatcher); + if (source.id !== id) { + throw new Error('Expected Source id to be ' + id + ' instead of ' + source.id); + } + util.bindAll([ + 'load', + 'abort', + 'unload', + 'serialize', + 'prepare' + ], source); + return source; +}; +exports.getType = function (name) { + return sourceTypes[name]; +}; +exports.setType = function (name, type) { + sourceTypes[name] = type; +}; +},{"../source/geojson_source":102,"../source/image_source":105,"../source/raster_tile_source":109,"../source/vector_tile_source":114,"../source/video_source":116,"../util/util":188}],111:[function(require,module,exports){ +'use strict'; +var Source = require('./source'); +var Tile = require('./tile'); +var Evented = require('../util/evented'); +var TileCoord = require('./tile_coord'); +var Cache = require('../util/lru_cache'); +var Coordinate = require('../geo/coordinate'); +var util = require('../util/util'); +var EXTENT = require('../data/bucket').EXTENT; +module.exports = SourceCache; +function SourceCache(id, options, dispatcher) { + this.id = id; + this.dispatcher = dispatcher; + var source = this._source = Source.create(id, options, dispatcher); + source.setEventedParent(this); + this.on('source.load', function () { + if (this.map && this._source.onAdd) { + this._source.onAdd(this.map); + } + this._sourceLoaded = true; + }); + this.on('error', function () { + this._sourceErrored = true; + }); + this.on('data', function (event) { + if (this._sourceLoaded && event.dataType === 'source') { + this.reload(); + if (this.transform) { + this.update(this.transform, this.map && this.map.style.rasterFadeDuration); } } - - var scale = tr.zoomScale(zoom - startZoom), - from = tr.point, - to = 'center' in options ? tr.project(center).sub(offset.div(scale)) : from; - - var startWorldSize = tr.worldSize, - rho = options.curve, - - // w₀: Initial visible span, measured in pixels at the initial scale. - w0 = Math.max(tr.width, tr.height), - // w₁: Final visible span, measured in pixels with respect to the initial scale. - w1 = w0 / scale, - // Length of the flight path as projected onto the ground plane, measured in pixels from - // the world image origin at the initial scale. - u1 = to.sub(from).mag(); - - if ('minZoom' in options) { - var minZoom = util.clamp(Math.min(options.minZoom, startZoom, zoom), tr.minZoom, tr.maxZoom); - // wm: Maximum visible span, measured in pixels with respect to the initial - // scale. - var wMax = w0 / tr.zoomScale(minZoom - startZoom); - rho = Math.sqrt(wMax / u1 * 2); + }); + this._tiles = {}; + this._cache = new Cache(0, this.unloadTile.bind(this)); + this._isIdRenderable = this._isIdRenderable.bind(this); +} +SourceCache.maxOverzooming = 10; +SourceCache.maxUnderzooming = 3; +SourceCache.prototype = util.inherit(Evented, { + onAdd: function (map) { + this.map = map; + if (this._source && this._source.onAdd) { + this._source.onAdd(map); } - - // ρ² - var rho2 = rho * rho; - - /** - * rᵢ: Returns the zoom-out factor at one end of the animation. - * - * @param i 0 for the ascent or 1 for the descent. - * @private - */ - function r(i) { - var b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1); - return Math.log(Math.sqrt(b * b + 1) - b); + }, + loaded: function () { + if (this._sourceErrored) { + return true; } - - function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; } - function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; } - function tanh(n) { return sinh(n) / cosh(n); } - - // r₀: Zoom-out factor during ascent. - var r0 = r(0), - /** - * w(s): Returns the visible span on the ground, measured in pixels with respect to the - * initial scale. - * - * Assumes an angular field of view of 2 arctan ½ ≈ 53°. - * @private - */ - w = function (s) { return (cosh(r0) / cosh(r0 + rho * s)); }, - /** - * u(s): Returns the distance along the flight path as projected onto the ground plane, - * measured in pixels from the world image origin at the initial scale. - * @private - */ - u = function (s) { return w0 * ((cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2) / u1; }, - // S: Total length of the flight path, measured in ρ-screenfuls. - S = (r(1) - r0) / rho; - - // When u₀ = u₁, the optimal path doesn’t require both ascent and descent. - if (Math.abs(u1) < 0.000001) { - // Perform a more or less instantaneous transition if the path is too short. - if (Math.abs(w0 - w1) < 0.000001) return this.easeTo(options); - - var k = w1 < w0 ? -1 : 1; - S = Math.abs(Math.log(w1 / w0)) / rho; - - u = function() { return 0; }; - w = function(s) { return Math.exp(k * rho * s); }; + if (!this._sourceLoaded) { + return false; } - - if ('duration' in options) { - options.duration = +options.duration; - } else { - var V = 'screenSpeed' in options ? +options.screenSpeed / rho : +options.speed; - options.duration = 1000 * S / V; + for (var t in this._tiles) { + var tile = this._tiles[t]; + if (tile.state !== 'loaded' && tile.state !== 'errored') + return false; } - - this.zooming = true; - if (startBearing !== bearing) this.rotating = true; - if (startPitch !== pitch) this.pitching = true; - - this.fire('movestart', eventData); - this.fire('zoomstart', eventData); - - this._ease(function (k) { - // s: The distance traveled along the flight path, measured in ρ-screenfuls. - var s = k * S, - us = u(s); - - tr.zoom = startZoom + tr.scaleZoom(1 / w(s)); - tr.center = tr.unproject(from.add(to.sub(from).mult(us)), startWorldSize); - - if (this.rotating) { - tr.bearing = interpolate(startBearing, bearing, k); - } - if (this.pitching) { - tr.pitch = interpolate(startPitch, pitch, k); - } - - this.fire('move', eventData); - this.fire('zoom', eventData); - if (this.rotating) { - this.fire('rotate', eventData); - } - if (this.pitching) { - this.fire('pitch', eventData); - } - }, function() { - this.fire('zoomend', eventData); - this.fire('moveend', eventData); - this.zooming = false; - this.rotating = false; - this.pitching = false; - }, options); - - return this; + return true; }, - - isEasing: function() { - return !!this._abortFn; + getSource: function () { + return this._source; }, - - /** - * Stop current animation - * - * @returns {Map} `this` - */ - stop: function() { - if (this._abortFn) { - this._abortFn(); - this._finishEase(); - } - return this; + loadTile: function (tile, callback) { + return this._source.loadTile(tile, callback); }, - - _ease: function(frame, finish, options) { - this._finishFn = finish; - this._abortFn = browser.timed(function (t) { - frame.call(this, options.easing(t)); - if (t === 1) { - this._finishEase(); - } - }, options.animate === false ? 0 : options.duration, this); + unloadTile: function (tile) { + if (this._source.unloadTile) + return this._source.unloadTile(tile); }, - - _finishEase: function() { - delete this._abortFn; - // The finish function might emit events which trigger new eases, which - // set a new _finishFn. Ensure we don't delete it unintentionally. - var finish = this._finishFn; - delete this._finishFn; - finish.call(this); + abortTile: function (tile) { + if (this._source.abortTile) + return this._source.abortTile(tile); }, - - // convert bearing so that it's numerically close to the current one so that it interpolates properly - _normalizeBearing: function(bearing, currentBearing) { - bearing = util.wrap(bearing, -180, 180); - var diff = Math.abs(bearing - currentBearing); - if (Math.abs(bearing - 360 - currentBearing) < diff) bearing -= 360; - if (Math.abs(bearing + 360 - currentBearing) < diff) bearing += 360; - return bearing; + serialize: function () { + return this._source.serialize(); }, - - _updateEasing: function(duration, zoom, bezier) { - var easing; - - if (this.ease) { - var ease = this.ease, - t = (Date.now() - ease.start) / ease.duration, - speed = ease.easing(t + 0.01) - ease.easing(t), - - // Quick hack to make new bezier that is continuous with last - x = 0.27 / Math.sqrt(speed * speed + 0.0001) * 0.01, - y = Math.sqrt(0.27 * 0.27 - x * x); - - easing = util.bezier(x, y, 0.25, 1); - } else { - easing = bezier ? util.bezier.apply(util, bezier) : util.ease; + prepare: function () { + if (this._sourceLoaded && this._source.prepare) + return this._source.prepare(); + }, + getIds: function () { + return Object.keys(this._tiles).map(Number).sort(compareKeyZoom); + }, + getRenderableIds: function () { + return this.getIds().filter(this._isIdRenderable); + }, + _isIdRenderable: function (id) { + return this._tiles[id].hasData() && !this._coveredTiles[id]; + }, + reload: function () { + this._cache.reset(); + for (var i in this._tiles) { + var tile = this._tiles[i]; + if (tile.state !== 'loading') { + tile.state = 'reloading'; + } + this.loadTile(this._tiles[i], this._tileLoaded.bind(this, this._tiles[i])); } - - // store information on current easing - this.ease = { - start: (new Date()).getTime(), - to: Math.pow(2, zoom), - duration: duration, - easing: easing - }; - - return easing; - } -}); - -},{"../geo/lng_lat":26,"../geo/lng_lat_bounds":27,"../util/browser":102,"../util/interpolate":109,"../util/util":113,"point-geometry":162}],86:[function(require,module,exports){ -'use strict'; - -var Control = require('./control'); -var DOM = require('../../util/dom'); -var util = require('../../util/util'); - -module.exports = Attribution; - -/** - * Creates an attribution control - * @class Attribution - * @param {Object} [options] - * @param {string} [options.position='bottom-right'] A string indicating the control's position on the map. Options are `top-right`, `top-left`, `bottom-right`, `bottom-left` - * @example - * var map = new mapboxgl.Map({attributionControl: false}) - * .addControl(new mapboxgl.Navigation({position: 'top-left'})); - */ -function Attribution(options) { - util.setOptions(this, options); -} - -Attribution.prototype = util.inherit(Control, { - options: { - position: 'bottom-right' }, - - onAdd: function(map) { - var className = 'mapboxgl-ctrl-attrib', - container = this._container = DOM.create('div', className, map.getContainer()); - - this._update(); - map.on('source.load', this._update.bind(this)); - map.on('source.change', this._update.bind(this)); - map.on('source.remove', this._update.bind(this)); - map.on('moveend', this._updateEditLink.bind(this)); - - return container; + _tileLoaded: function (tile, err) { + if (err) { + tile.state = 'errored'; + this._source.fire('error', { + tile: tile, + error: err + }); + return; + } + tile.sourceCache = this; + tile.timeAdded = new Date().getTime(); + this._source.fire('data', { + tile: tile, + dataType: 'tile' + }); + if (this.map) + this.map.painter.tileExtentVAO.vao = null; }, - - _update: function() { - var attributions = []; - - if (this._map.style) { - for (var id in this._map.style.sources) { - var source = this._map.style.sources[id]; - if (source.attribution && attributions.indexOf(source.attribution) < 0) { - attributions.push(source.attribution); + getTile: function (coord) { + return this.getTileByID(coord.id); + }, + getTileByID: function (id) { + return this._tiles[id]; + }, + getZoom: function (transform) { + return transform.zoom + transform.scaleZoom(transform.tileSize / this._source.tileSize); + }, + findLoadedChildren: function (coord, maxCoveringZoom, retain) { + var found = false; + for (var id in this._tiles) { + var tile = this._tiles[id]; + if (retain[id] || !tile.hasData() || tile.coord.z <= coord.z || tile.coord.z > maxCoveringZoom) + continue; + var z2 = Math.pow(2, Math.min(tile.coord.z, this._source.maxzoom) - Math.min(coord.z, this._source.maxzoom)); + if (Math.floor(tile.coord.x / z2) !== coord.x || Math.floor(tile.coord.y / z2) !== coord.y) + continue; + retain[id] = true; + found = true; + while (tile && tile.coord.z - 1 > coord.z) { + var parentId = tile.coord.parent(this._source.maxzoom).id; + tile = this._tiles[parentId]; + if (tile && tile.hasData()) { + delete retain[id]; + retain[parentId] = true; } } } - - this._container.innerHTML = attributions.join(' | '); - this._editLink = this._container.getElementsByClassName('mapbox-improve-map')[0]; - this._updateEditLink(); + return found; }, - - _updateEditLink: function() { - if (this._editLink) { - var center = this._map.getCenter(); - this._editLink.href = 'https://www.mapbox.com/map-feedback/#/' + - center.lng + '/' + center.lat + '/' + Math.round(this._map.getZoom() + 1); - } - } -}); - -},{"../../util/dom":105,"../../util/util":113,"./control":87}],87:[function(require,module,exports){ -'use strict'; - -module.exports = Control; - -/** - * A base class for map-related interface elements. - * - * @class Control - */ -function Control() {} - -Control.prototype = { - /** - * Add this control to the map, returning the control itself - * for chaining. This will insert the control's DOM element into - * the map's DOM element if the control has a `position` specified. - * - * @param {Map} map - * @returns {Control} `this` - */ - addTo: function(map) { - this._map = map; - var container = this._container = this.onAdd(map); - if (this.options && this.options.position) { - var pos = this.options.position; - var corner = map._controlCorners[pos]; - container.className += ' mapboxgl-ctrl'; - if (pos.indexOf('bottom') !== -1) { - corner.insertBefore(container, corner.firstChild); - } else { - corner.appendChild(container); + findLoadedParent: function (coord, minCoveringZoom, retain) { + for (var z = coord.z - 1; z >= minCoveringZoom; z--) { + coord = coord.parent(this._source.maxzoom); + var tile = this._tiles[coord.id]; + if (tile && tile.hasData()) { + retain[coord.id] = true; + return tile; + } + if (this._cache.has(coord.id)) { + this.addTile(coord); + retain[coord.id] = true; + return this._tiles[coord.id]; } } - - return this; }, - - /** - * Remove this control from the map it has been added to. - * - * @returns {Control} `this` - */ - remove: function() { - this._container.parentNode.removeChild(this._container); - if (this.onRemove) this.onRemove(this._map); - this._map = null; - return this; - } -}; - -},{}],88:[function(require,module,exports){ -'use strict'; - -var Control = require('./control'); -var DOM = require('../../util/dom'); -var util = require('../../util/util'); - -module.exports = Navigation; - -/** - * Creates a navigation control with zoom buttons and a compass - * @class Navigation - * @param {Object} [options] - * @param {string} [options.position='top-right'] A string indicating the control's position on the map. Options are `top-right`, `top-left`, `bottom-right`, `bottom-left` - * @example - * map.addControl(new mapboxgl.Navigation({position: 'top-left'})); // position is optional - */ -function Navigation(options) { - util.setOptions(this, options); -} - -Navigation.prototype = util.inherit(Control, { - options: { - position: 'top-right' + updateCacheSize: function (transform) { + var widthInTiles = Math.ceil(transform.width / transform.tileSize) + 1; + var heightInTiles = Math.ceil(transform.height / transform.tileSize) + 1; + var approxTilesInView = widthInTiles * heightInTiles; + var commonZoomRange = 5; + this._cache.setMaxSize(Math.floor(approxTilesInView * commonZoomRange)); }, - - onAdd: function(map) { - var className = 'mapboxgl-ctrl'; - - var container = this._container = DOM.create('div', className + '-group', map.getContainer()); - this._container.addEventListener('contextmenu', this._onContextMenu.bind(this)); - - this._zoomInButton = this._createButton(className + '-icon ' + className + '-zoom-in', map.zoomIn.bind(map)); - this._zoomOutButton = this._createButton(className + '-icon ' + className + '-zoom-out', map.zoomOut.bind(map)); - this._compass = this._createButton(className + '-icon ' + className + '-compass', map.resetNorth.bind(map)); - - this._compassArrow = DOM.create('div', 'arrow', this._compass); - - this._compass.addEventListener('mousedown', this._onCompassDown.bind(this)); - this._onCompassMove = this._onCompassMove.bind(this); - this._onCompassUp = this._onCompassUp.bind(this); - - map.on('rotate', this._rotateCompassArrow.bind(this)); - this._rotateCompassArrow(); - - this._el = map.getCanvasContainer(); - - return container; + update: function (transform, fadeDuration) { + if (!this._sourceLoaded) { + return; + } + var i; + var coord; + var tile; + this.updateCacheSize(transform); + var zoom = (this._source.roundZoom ? Math.round : Math.floor)(this.getZoom(transform)); + var minCoveringZoom = Math.max(zoom - SourceCache.maxOverzooming, this._source.minzoom); + var maxCoveringZoom = Math.max(zoom + SourceCache.maxUnderzooming, this._source.minzoom); + var retain = {}; + var now = new Date().getTime(); + this._coveredTiles = {}; + var visibleCoords; + if (!this.used) { + visibleCoords = []; + } else if (this._source.coord) { + visibleCoords = [this._source.coord]; + } else { + visibleCoords = transform.coveringTiles({ + tileSize: this._source.tileSize, + minzoom: this._source.minzoom, + maxzoom: this._source.maxzoom, + roundZoom: this._source.roundZoom, + reparseOverscaled: this._source.reparseOverscaled + }); + } + for (i = 0; i < visibleCoords.length; i++) { + coord = visibleCoords[i]; + tile = this.addTile(coord); + retain[coord.id] = true; + if (tile.hasData()) + continue; + if (!this.findLoadedChildren(coord, maxCoveringZoom, retain)) { + this.findLoadedParent(coord, minCoveringZoom, retain); + } + } + var parentsForFading = {}; + var ids = Object.keys(retain); + for (var k = 0; k < ids.length; k++) { + var id = ids[k]; + coord = TileCoord.fromID(id); + tile = this._tiles[id]; + if (tile && tile.timeAdded > now - (fadeDuration || 0)) { + if (this.findLoadedChildren(coord, maxCoveringZoom, retain)) { + retain[id] = true; + } + this.findLoadedParent(coord, minCoveringZoom, parentsForFading); + } + } + var fadedParent; + for (fadedParent in parentsForFading) { + if (!retain[fadedParent]) { + this._coveredTiles[fadedParent] = true; + } + } + for (fadedParent in parentsForFading) { + retain[fadedParent] = true; + } + var remove = util.keysDifference(this._tiles, retain); + for (i = 0; i < remove.length; i++) { + this.removeTile(+remove[i]); + } + this.transform = transform; }, - - _onContextMenu: function(e) { - e.preventDefault(); + addTile: function (coord) { + var tile = this._tiles[coord.id]; + if (tile) + return tile; + var wrapped = coord.wrapped(); + tile = this._tiles[wrapped.id]; + if (!tile) { + tile = this._cache.get(wrapped.id); + if (tile && this._redoPlacement) { + this._redoPlacement(tile); + } + } + if (!tile) { + var zoom = coord.z; + var overscaling = zoom > this._source.maxzoom ? Math.pow(2, zoom - this._source.maxzoom) : 1; + tile = new Tile(wrapped, this._source.tileSize * overscaling, this._source.maxzoom); + this.loadTile(tile, this._tileLoaded.bind(this, tile)); + } + tile.uses++; + this._tiles[coord.id] = tile; + this._source.fire('dataloading', { + tile: tile, + dataType: 'tile' + }); + return tile; }, - - _onCompassDown: function(e) { - if (e.button !== 0) return; - - DOM.disableDrag(); - document.addEventListener('mousemove', this._onCompassMove); - document.addEventListener('mouseup', this._onCompassUp); - - this._el.dispatchEvent(copyMouseEvent(e)); - e.stopPropagation(); + removeTile: function (id) { + var tile = this._tiles[id]; + if (!tile) + return; + tile.uses--; + delete this._tiles[id]; + this._source.fire('data', { dataType: 'tile' }); + if (tile.uses > 0) + return; + if (tile.hasData()) { + this._cache.add(tile.coord.wrapped().id, tile); + } else { + tile.aborted = true; + this.abortTile(tile); + this.unloadTile(tile); + } }, - - _onCompassMove: function(e) { - if (e.button !== 0) return; - - this._el.dispatchEvent(copyMouseEvent(e)); - e.stopPropagation(); + clearTiles: function () { + for (var id in this._tiles) + this.removeTile(id); + this._cache.reset(); }, - - _onCompassUp: function(e) { - if (e.button !== 0) return; - - document.removeEventListener('mousemove', this._onCompassMove); - document.removeEventListener('mouseup', this._onCompassUp); - DOM.enableDrag(); - - this._el.dispatchEvent(copyMouseEvent(e)); - e.stopPropagation(); + tilesIn: function (queryGeometry) { + var tileResults = {}; + var ids = this.getIds(); + var minX = Infinity; + var minY = Infinity; + var maxX = -Infinity; + var maxY = -Infinity; + var z = queryGeometry[0].zoom; + for (var k = 0; k < queryGeometry.length; k++) { + var p = queryGeometry[k]; + minX = Math.min(minX, p.column); + minY = Math.min(minY, p.row); + maxX = Math.max(maxX, p.column); + maxY = Math.max(maxY, p.row); + } + for (var i = 0; i < ids.length; i++) { + var tile = this._tiles[ids[i]]; + var coord = TileCoord.fromID(ids[i]); + var tileSpaceBounds = [ + coordinateToTilePoint(coord, tile.sourceMaxZoom, new Coordinate(minX, minY, z)), + coordinateToTilePoint(coord, tile.sourceMaxZoom, new Coordinate(maxX, maxY, z)) + ]; + if (tileSpaceBounds[0].x < EXTENT && tileSpaceBounds[0].y < EXTENT && tileSpaceBounds[1].x >= 0 && tileSpaceBounds[1].y >= 0) { + var tileSpaceQueryGeometry = []; + for (var j = 0; j < queryGeometry.length; j++) { + tileSpaceQueryGeometry.push(coordinateToTilePoint(coord, tile.sourceMaxZoom, queryGeometry[j])); + } + var tileResult = tileResults[tile.coord.id]; + if (tileResult === undefined) { + tileResult = tileResults[tile.coord.id] = { + tile: tile, + coord: coord, + queryGeometry: [], + scale: Math.pow(2, this.transform.zoom - tile.coord.z) + }; + } + tileResult.queryGeometry.push(tileSpaceQueryGeometry); + } + } + var results = []; + for (var t in tileResults) { + results.push(tileResults[t]); + } + return results; }, - - _createButton: function(className, fn) { - var a = DOM.create('button', className, this._container); - a.addEventListener('click', function() { fn(); }); - return a; + redoPlacement: function () { + var ids = this.getIds(); + for (var i = 0; i < ids.length; i++) { + var tile = this.getTileByID(ids[i]); + tile.redoPlacement(this); + } }, - - _rotateCompassArrow: function() { - var rotate = 'rotate(' + (this._map.transform.angle * (180 / Math.PI)) + 'deg)'; - this._compassArrow.style.transform = rotate; + getVisibleCoordinates: function () { + return this.getRenderableIds().map(TileCoord.fromID); } }); - - -function copyMouseEvent(e) { - return new MouseEvent(e.type, { - button: 2, // right click - buttons: 2, // right click - bubbles: true, - cancelable: true, - detail: e.detail, - view: e.view, - screenX: e.screenX, - screenY: e.screenY, - clientX: e.clientX, - clientY: e.clientY, - movementX: e.movementX, - movementY: e.movementY, - ctrlKey: e.ctrlKey, - shiftKey: e.shiftKey, - altKey: e.altKey, - metaKey: e.metaKey - }); +function coordinateToTilePoint(tileCoord, sourceMaxZoom, coord) { + var zoomedCoord = coord.zoomTo(Math.min(tileCoord.z, sourceMaxZoom)); + return { + x: (zoomedCoord.column - (tileCoord.x + tileCoord.w * Math.pow(2, tileCoord.z))) * EXTENT, + y: (zoomedCoord.row - tileCoord.y) * EXTENT + }; } - - -},{"../../util/dom":105,"../../util/util":113,"./control":87}],89:[function(require,module,exports){ +function compareKeyZoom(a, b) { + return a % 32 - b % 32; +} +},{"../data/bucket":72,"../geo/coordinate":81,"../util/evented":179,"../util/lru_cache":184,"../util/util":188,"./source":110,"./tile":112,"./tile_coord":113}],112:[function(require,module,exports){ 'use strict'; - -var DOM = require('../../util/dom'), - LngLatBounds = require('../../geo/lng_lat_bounds'), - util = require('../../util/util'); - -module.exports = BoxZoomHandler; - -/** - * The `BoxZoomHandler` allows a user to zoom the map to fit a bounding box. - * The bounding box is defined by holding `shift` while dragging the cursor. - * @class BoxZoomHandler - */ -function BoxZoomHandler(map) { - this._map = map; - this._el = map.getCanvasContainer(); - this._container = map.getContainer(); - - util.bindHandlers(this); +var util = require('../util/util'); +var Bucket = require('../data/bucket'); +var FeatureIndex = require('../data/feature_index'); +var vt = require('vector-tile'); +var Protobuf = require('pbf'); +var GeoJSONFeature = require('../util/vectortile_to_geojson'); +var featureFilter = require('feature-filter'); +var CollisionTile = require('../symbol/collision_tile'); +var CollisionBoxArray = require('../symbol/collision_box'); +var SymbolInstancesArray = require('../symbol/symbol_instances'); +var SymbolQuadsArray = require('../symbol/symbol_quads'); +module.exports = Tile; +function Tile(coord, size, sourceMaxZoom) { + this.coord = coord; + this.uid = util.uniqueId(); + this.uses = 0; + this.tileSize = size; + this.sourceMaxZoom = sourceMaxZoom; + this.buckets = {}; + this.state = 'loading'; } - -BoxZoomHandler.prototype = { - - /** - * Enable the "box zoom" interaction. - * @example - * map.boxZoom.enable(); - */ - enable: function () { - this.disable(); - this._el.addEventListener('mousedown', this._onMouseDown, false); - }, - - /** - * Disable the "box zoom" interaction. - * @example - * map.boxZoom.disable(); - */ - disable: function () { - this._el.removeEventListener('mousedown', this._onMouseDown); - }, - - _onMouseDown: function (e) { - if (!(e.shiftKey && e.button === 0)) return; - - document.addEventListener('mousemove', this._onMouseMove, false); - document.addEventListener('keydown', this._onKeyDown, false); - document.addEventListener('mouseup', this._onMouseUp, false); - - DOM.disableDrag(); - this._startPos = DOM.mousePos(this._el, e); - this.active = true; - }, - - _onMouseMove: function (e) { - var p0 = this._startPos, - p1 = DOM.mousePos(this._el, e); - - if (!this._box) { - this._box = DOM.create('div', 'mapboxgl-boxzoom', this._container); - this._container.classList.add('mapboxgl-crosshair'); - this._fireEvent('boxzoomstart', e); +Tile.prototype = { + loadVectorData: function (data, painter) { + if (this.hasData()) { + this.unloadVectorData(painter); } - - var minX = Math.min(p0.x, p1.x), - maxX = Math.max(p0.x, p1.x), - minY = Math.min(p0.y, p1.y), - maxY = Math.max(p0.y, p1.y); - - DOM.setTransform(this._box, 'translate(' + minX + 'px,' + minY + 'px)'); - - this._box.style.width = (maxX - minX) + 'px'; - this._box.style.height = (maxY - minY) + 'px'; - }, - - _onMouseUp: function (e) { - if (e.button !== 0) return; - - var p0 = this._startPos, - p1 = DOM.mousePos(this._el, e), - bounds = new LngLatBounds(this._map.unproject(p0), this._map.unproject(p1)); - - this._finish(); - - if (p0.x === p1.x && p0.y === p1.y) { - this._fireEvent('boxzoomcancel', e); - } else { - this._map - .fitBounds(bounds, {linear: true}) - .fire('boxzoomend', { originalEvent: e, boxZoomBounds: bounds }); + this.state = 'loaded'; + if (!data) + return; + if (data.rawTileData) { + this.rawTileData = data.rawTileData; + } + this.collisionBoxArray = new CollisionBoxArray(data.collisionBoxArray); + this.collisionTile = new CollisionTile(data.collisionTile, this.collisionBoxArray); + this.symbolInstancesArray = new SymbolInstancesArray(data.symbolInstancesArray); + this.symbolQuadsArray = new SymbolQuadsArray(data.symbolQuadsArray); + this.featureIndex = new FeatureIndex(data.featureIndex, this.rawTileData, this.collisionTile); + this.buckets = unserializeBuckets(data.buckets, painter.style); + }, + reloadSymbolData: function (data, painter, style) { + if (this.state === 'unloaded') + return; + this.collisionTile = new CollisionTile(data.collisionTile, this.collisionBoxArray); + this.featureIndex.setCollisionTile(this.collisionTile); + for (var id in this.buckets) { + var bucket = this.buckets[id]; + if (bucket.type === 'symbol') { + bucket.destroy(painter.gl); + delete this.buckets[id]; + } } + util.extend(this.buckets, unserializeBuckets(data.buckets, style)); }, - - _onKeyDown: function (e) { - if (e.keyCode === 27) { - this._finish(); - this._fireEvent('boxzoomcancel', e); + unloadVectorData: function (painter) { + for (var id in this.buckets) { + var bucket = this.buckets[id]; + bucket.destroy(painter.gl); } + this.collisionBoxArray = null; + this.symbolQuadsArray = null; + this.symbolInstancesArray = null; + this.collisionTile = null; + this.featureIndex = null; + this.buckets = null; + this.state = 'unloaded'; }, - - _finish: function () { - this.active = false; - - document.removeEventListener('mousemove', this._onMouseMove, false); - document.removeEventListener('keydown', this._onKeyDown, false); - document.removeEventListener('mouseup', this._onMouseUp, false); - - this._container.classList.remove('mapboxgl-crosshair'); - - if (this._box) { - this._box.parentNode.removeChild(this._box); - this._box = null; + redoPlacement: function (source) { + if (this.state !== 'loaded' || this.state === 'reloading') { + this.redoWhenDone = true; + return; } - - DOM.enableDrag(); - }, - - _fireEvent: function (type, e) { - return this._map.fire(type, { originalEvent: e }); - } -}; - - -/** - * Boxzoom start event. This event is emitted at the start of a box zoom interaction. - * - * @event boxzoomstart - * @memberof Map - * @instance - * @property {EventData} data Original event data - */ - -/** - * Boxzoom end event. This event is emitted at the end of a box zoom interaction - * - * @event boxzoomend - * @memberof Map - * @instance - * @type {Object} - * @property {Event} originalEvent the original DOM event - * @property {LngLatBounds} boxZoomBounds the bounds of the box zoom target - */ - -/** - * Boxzoom cancel event. This event is emitted when the user cancels a box zoom interaction, - * or when the box zoom does not meet the minimum size threshold. - * - * @event boxzoomcancel - * @memberof Map - * @instance - * @property {EventData} data Original event data - */ - -},{"../../geo/lng_lat_bounds":27,"../../util/dom":105,"../../util/util":113}],90:[function(require,module,exports){ -'use strict'; - -module.exports = DoubleClickZoomHandler; - -/** - * The `DoubleClickZoomHandler` allows a user to zoom the map around point by - * double clicking. - * @class DoubleClickZoomHandler - */ -function DoubleClickZoomHandler(map) { - this._map = map; - this._onDblClick = this._onDblClick.bind(this); -} - -DoubleClickZoomHandler.prototype = { - - /** - * Enable the "double click to zoom" interaction. - * @example - * map.doubleClickZoom.enable(); - */ - enable: function () { - this.disable(); - this._map.on('dblclick', this._onDblClick); - }, - - /** - * Disable the "double click to zoom" interaction. - * @example - * map.doubleClickZoom.disable(); - */ - disable: function () { - this._map.off('dblclick', this._onDblClick); - }, - - _onDblClick: function (e) { - this._map.zoomTo(this._map.getZoom() + - (e.originalEvent.shiftKey ? -1 : 1), {around: e.lngLat}); - } -}; - -},{}],91:[function(require,module,exports){ -'use strict'; - -var DOM = require('../../util/dom'), - util = require('../../util/util'); - -module.exports = DragPanHandler; - -var inertiaLinearity = 0.3, - inertiaEasing = util.bezier(0, 0, inertiaLinearity, 1), - inertiaMaxSpeed = 1400, // px/s - inertiaDeceleration = 2500; // px/s^2 - - -/** - * The `DragPanHandler` allows a user to pan the map by clicking and dragging - * the cursor. - * @class DragPanHandler - */ -function DragPanHandler(map) { - this._map = map; - this._el = map.getCanvasContainer(); - - util.bindHandlers(this); -} - -DragPanHandler.prototype = { - - /** - * Enable the "drag to pan" interaction. - * @example - * map.dragPan.enable(); - */ - enable: function () { - this.disable(); - this._el.addEventListener('mousedown', this._onDown); - this._el.addEventListener('touchstart', this._onDown); - }, - - /** - * Disable the "drag to pan" interaction. - * @example - * map.dragPan.disable(); - */ - disable: function () { - this._el.removeEventListener('mousedown', this._onDown); - this._el.removeEventListener('touchstart', this._onDown); - }, - - _onDown: function (e) { - if (this._ignoreEvent(e)) return; - if (this.active) return; - - if (e.touches) { - document.addEventListener('touchmove', this._onMove); - document.addEventListener('touchend', this._onTouchEnd); - } else { - document.addEventListener('mousemove', this._onMove); - document.addEventListener('mouseup', this._onMouseUp); + this.state = 'reloading'; + source.dispatcher.send('redo placement', { + uid: this.uid, + source: source.id, + angle: source.map.transform.angle, + pitch: source.map.transform.pitch, + showCollisionBoxes: source.map.showCollisionBoxes + }, done.bind(this), this.workerID); + function done(_, data) { + this.reloadSymbolData(data, source.map.painter, source.map.style); + source.fire('data', { + tile: this, + dataType: 'tile' + }); + if (source.map) + source.map.painter.tileExtentVAO.vao = null; + this.state = 'loaded'; + if (this.redoWhenDone) { + this.redoPlacement(source); + this.redoWhenDone = false; + } } - - this.active = false; - this._startPos = this._pos = DOM.mousePos(this._el, e); - this._inertia = [[Date.now(), this._pos]]; }, - - _onMove: function (e) { - if (this._ignoreEvent(e)) return; - - if (!this.active) { - this.active = true; - this._fireEvent('dragstart', e); - this._fireEvent('movestart', e); - } - - var pos = DOM.mousePos(this._el, e), - map = this._map; - - map.stop(); - this._drainInertiaBuffer(); - this._inertia.push([Date.now(), pos]); - - map.transform.setLocationAtPoint(map.transform.pointLocation(this._pos), pos); - - this._fireEvent('drag', e); - this._fireEvent('move', e); - - this._pos = pos; - - e.preventDefault(); + getBucket: function (layer) { + return this.buckets && this.buckets[layer.ref || layer.id]; }, - - _onUp: function (e) { - if (!this.active) return; - - this.active = false; - this._fireEvent('dragend', e); - this._drainInertiaBuffer(); - - var finish = function() { - this._fireEvent('moveend', e); - }.bind(this); - - var inertia = this._inertia; - if (inertia.length < 2) { - finish(); + querySourceFeatures: function (result, params) { + if (!this.rawTileData) return; + if (!this.vtLayers) { + this.vtLayers = new vt.VectorTile(new Protobuf(this.rawTileData)).layers; } - - var last = inertia[inertia.length - 1], - first = inertia[0], - flingOffset = last[1].sub(first[1]), - flingDuration = (last[0] - first[0]) / 1000; - - if (flingDuration === 0 || last[1].equals(first[1])) { - finish(); + var layer = this.vtLayers._geojsonTileLayer || this.vtLayers[params.sourceLayer]; + if (!layer) return; - } - - // calculate px/s velocity & adjust for increased initial animation speed when easing out - var velocity = flingOffset.mult(inertiaLinearity / flingDuration), - speed = velocity.mag(); // px/s - - if (speed > inertiaMaxSpeed) { - speed = inertiaMaxSpeed; - velocity._unit()._mult(speed); - } - - var duration = speed / (inertiaDeceleration * inertiaLinearity), - offset = velocity.mult(-duration / 2); - - this._map.panBy(offset, { - duration: duration * 1000, - easing: inertiaEasing, - noMoveStart: true - }, { originalEvent: e }); - }, - - _onMouseUp: function (e) { - if (this._ignoreEvent(e)) return; - this._onUp(e); - document.removeEventListener('mousemove', this._onMove); - document.removeEventListener('mouseup', this._onMouseUp); - }, - - _onTouchEnd: function (e) { - if (this._ignoreEvent(e)) return; - this._onUp(e); - document.removeEventListener('touchmove', this._onMove); - document.removeEventListener('touchend', this._onTouchEnd); - }, - - _fireEvent: function (type, e) { - return this._map.fire(type, { originalEvent: e }); - }, - - _ignoreEvent: function (e) { - var map = this._map; - - if (map.boxZoom && map.boxZoom.active) return true; - if (map.dragRotate && map.dragRotate.active) return true; - if (e.touches) { - return (e.touches.length > 1); - } else { - if (e.ctrlKey) return true; - var buttons = 1, // left button - button = 0; // left button - return (e.type === 'mousemove' ? e.buttons & buttons === 0 : e.button !== button); + var filter = featureFilter(params.filter); + var coord = { + z: this.coord.z, + x: this.coord.x, + y: this.coord.y + }; + for (var i = 0; i < layer.length; i++) { + var feature = layer.feature(i); + if (filter(feature)) { + var geojsonFeature = new GeoJSONFeature(feature, this.coord.z, this.coord.x, this.coord.y); + geojsonFeature.tile = coord; + result.push(geojsonFeature); + } } }, - - _drainInertiaBuffer: function () { - var inertia = this._inertia, - now = Date.now(), - cutoff = 160; // msec - - while (inertia.length > 0 && now - inertia[0][0] > cutoff) inertia.shift(); + hasData: function () { + return this.state === 'loaded' || this.state === 'reloading'; } }; - - -/** - * Drag start event. This event is emitted at the start of a user-initiated pan interaction. - * - * @event dragstart - * @memberof Map - * @instance - * @property {EventData} data Original event data - */ - -/** - * Drag event. This event is emitted repeatedly during a user-initiated pan interaction. - * - * @event drag - * @memberof Map - * @instance - * @property {EventData} data Original event data - */ - -/** - * Drag end event. This event is emitted at the end of a user-initiated pan interaction. - * - * @event dragend - * @memberof Map - * @instance - * @property {EventData} data Original event data - */ - -},{"../../util/dom":105,"../../util/util":113}],92:[function(require,module,exports){ +function unserializeBuckets(input, style) { + if (!style) + return; + var output = {}; + for (var i = 0; i < input.length; i++) { + var layer = style.getLayer(input[i].layerId); + if (!layer) + continue; + var bucket = Bucket.create(util.extend({ + layer: layer, + childLayers: input[i].childLayerIds.map(style.getLayer.bind(style)).filter(function (layer) { + return layer; + }) + }, input[i])); + output[bucket.id] = bucket; + } + return output; +} +},{"../data/bucket":72,"../data/feature_index":79,"../symbol/collision_box":138,"../symbol/collision_tile":140,"../symbol/symbol_instances":149,"../symbol/symbol_quads":150,"../util/util":188,"../util/vectortile_to_geojson":189,"feature-filter":12,"pbf":192,"vector-tile":212}],113:[function(require,module,exports){ 'use strict'; - -var DOM = require('../../util/dom'), - Point = require('point-geometry'), - util = require('../../util/util'); - -module.exports = DragRotateHandler; - -var inertiaLinearity = 0.25, - inertiaEasing = util.bezier(0, 0, inertiaLinearity, 1), - inertiaMaxSpeed = 180, // deg/s - inertiaDeceleration = 720; // deg/s^2 - - -/** - * The `DragRotateHandler` allows a user to rotate the map by clicking and - * dragging the cursor while holding the right mouse button or the `ctrl` key. - * @class DragRotateHandler - */ -function DragRotateHandler(map) { - this._map = map; - this._el = map.getCanvasContainer(); - - util.bindHandlers(this); +var WhooTS = require('whoots-js'); +var Coordinate = require('../geo/coordinate'); +module.exports = TileCoord; +function TileCoord(z, x, y, w) { + if (isNaN(w)) + w = 0; + this.z = +z; + this.x = +x; + this.y = +y; + this.w = +w; + w *= 2; + if (w < 0) + w = w * -1 - 1; + var dim = 1 << this.z; + this.id = (dim * dim * w + dim * this.y + this.x) * 32 + this.z; + this.posMatrix = null; } - -DragRotateHandler.prototype = { - - /** - * Enable the "drag to rotate" interaction. - * @example - * map.dragRotate.enable(); - */ - enable: function () { - this.disable(); - this._el.addEventListener('mousedown', this._onDown); - }, - - /** - * Disable the "drag to rotate" interaction. - * @example - * map.dragRotate.disable(); - */ - disable: function () { - this._el.removeEventListener('mousedown', this._onDown); - }, - - _onDown: function (e) { - if (this._ignoreEvent(e)) return; - if (this.active) return; - - document.addEventListener('mousemove', this._onMove); - document.addEventListener('mouseup', this._onUp); - - this.active = false; - this._inertia = [[Date.now(), this._map.getBearing()]]; - this._startPos = this._pos = DOM.mousePos(this._el, e); - this._center = this._map.transform.centerPoint; // Center of rotation - - // If the first click was too close to the center, move the center of rotation by 200 pixels - // in the direction of the click. - var startToCenter = this._startPos.sub(this._center), - startToCenterDist = startToCenter.mag(); - - if (startToCenterDist < 200) { - this._center = this._startPos.add(new Point(-200, 0)._rotate(startToCenter.angle())); - } - - e.preventDefault(); - }, - - _onMove: function (e) { - if (this._ignoreEvent(e)) return; - - if (!this.active) { - this.active = true; - this._fireEvent('rotatestart', e); - this._fireEvent('movestart', e); - } - - var map = this._map; - map.stop(); - - var p1 = this._pos, - p2 = DOM.mousePos(this._el, e), - center = this._center, - bearingDiff = p1.sub(center).angleWith(p2.sub(center)) / Math.PI * 180, - bearing = map.getBearing() - bearingDiff, - inertia = this._inertia, - last = inertia[inertia.length - 1]; - - this._drainInertiaBuffer(); - inertia.push([Date.now(), map._normalizeBearing(bearing, last[1])]); - - map.transform.bearing = bearing; - - this._fireEvent('rotate', e); - this._fireEvent('move', e); - - this._pos = p2; - }, - - _onUp: function (e) { - if (this._ignoreEvent(e)) return; - document.removeEventListener('mousemove', this._onMove); - document.removeEventListener('mouseup', this._onUp); - - if (!this.active) return; - - this.active = false; - this._fireEvent('rotateend', e); - this._drainInertiaBuffer(); - - var map = this._map, - mapBearing = map.getBearing(), - inertia = this._inertia; - - var finish = function() { - if (Math.abs(mapBearing) < map.options.bearingSnap) { - map.resetNorth({noMoveStart: true}, { originalEvent: e }); - } else { - this._fireEvent('moveend', e); - } - }.bind(this); - - if (inertia.length < 2) { - finish(); - return; +TileCoord.prototype.toString = function () { + return this.z + '/' + this.x + '/' + this.y; +}; +TileCoord.prototype.toCoordinate = function (sourceMaxZoom) { + var zoom = Math.min(this.z, sourceMaxZoom); + var tileScale = Math.pow(2, zoom); + var row = this.y; + var column = this.x + tileScale * this.w; + return new Coordinate(column, row, zoom); +}; +TileCoord.fromID = function (id) { + var z = id % 32, dim = 1 << z; + var xy = (id - z) / 32; + var x = xy % dim, y = (xy - x) / dim % dim; + var w = Math.floor(xy / (dim * dim)); + if (w % 2 !== 0) + w = w * -1 - 1; + w /= 2; + return new TileCoord(z, x, y, w); +}; +function getQuadkey(z, x, y) { + var quadkey = '', mask; + for (var i = z; i > 0; i--) { + mask = 1 << i - 1; + quadkey += (x & mask ? 1 : 0) + (y & mask ? 2 : 0); + } + return quadkey; +} +TileCoord.prototype.url = function (urls, sourceMaxZoom, scheme) { + var bbox = WhooTS.getTileBBox(this.x, this.y, this.z); + var quadkey = getQuadkey(this.z, this.x, this.y); + return urls[(this.x + this.y) % urls.length].replace('{prefix}', (this.x % 16).toString(16) + (this.y % 16).toString(16)).replace('{z}', Math.min(this.z, sourceMaxZoom || this.z)).replace('{x}', this.x).replace('{y}', scheme === 'tms' ? Math.pow(2, this.z) - this.y - 1 : this.y).replace('{quadkey}', quadkey).replace('{bbox-epsg-3857}', bbox); +}; +TileCoord.prototype.parent = function (sourceMaxZoom) { + if (this.z === 0) + return null; + if (this.z > sourceMaxZoom) { + return new TileCoord(this.z - 1, this.x, this.y, this.w); + } + return new TileCoord(this.z - 1, Math.floor(this.x / 2), Math.floor(this.y / 2), this.w); +}; +TileCoord.prototype.wrapped = function () { + return new TileCoord(this.z, this.x, this.y, 0); +}; +TileCoord.prototype.children = function (sourceMaxZoom) { + if (this.z >= sourceMaxZoom) { + return [new TileCoord(this.z + 1, this.x, this.y, this.w)]; + } + var z = this.z + 1; + var x = this.x * 2; + var y = this.y * 2; + return [ + new TileCoord(z, x, y, this.w), + new TileCoord(z, x + 1, y, this.w), + new TileCoord(z, x, y + 1, this.w), + new TileCoord(z, x + 1, y + 1, this.w) + ]; +}; +function edge(a, b) { + if (a.row > b.row) { + var t = a; + a = b; + b = t; + } + return { + x0: a.column, + y0: a.row, + x1: b.column, + y1: b.row, + dx: b.column - a.column, + dy: b.row - a.row + }; +} +function scanSpans(e0, e1, ymin, ymax, scanLine) { + var y0 = Math.max(ymin, Math.floor(e1.y0)); + var y1 = Math.min(ymax, Math.ceil(e1.y1)); + if (e0.x0 === e1.x0 && e0.y0 === e1.y0 ? e0.x0 + e1.dy / e0.dy * e0.dx < e1.x1 : e0.x1 - e1.dy / e0.dy * e0.dx < e1.x0) { + var t = e0; + e0 = e1; + e1 = t; + } + var m0 = e0.dx / e0.dy; + var m1 = e1.dx / e1.dy; + var d0 = e0.dx > 0; + var d1 = e1.dx < 0; + for (var y = y0; y < y1; y++) { + var x0 = m0 * Math.max(0, Math.min(e0.dy, y + d0 - e0.y0)) + e0.x0; + var x1 = m1 * Math.max(0, Math.min(e1.dy, y + d1 - e1.y0)) + e1.x0; + scanLine(Math.floor(x1), Math.ceil(x0), y); + } +} +function scanTriangle(a, b, c, ymin, ymax, scanLine) { + var ab = edge(a, b), bc = edge(b, c), ca = edge(c, a); + var t; + if (ab.dy > bc.dy) { + t = ab; + ab = bc; + bc = t; + } + if (ab.dy > ca.dy) { + t = ab; + ab = ca; + ca = t; + } + if (bc.dy > ca.dy) { + t = bc; + bc = ca; + ca = t; + } + if (ab.dy) + scanSpans(ca, ab, ymin, ymax, scanLine); + if (bc.dy) + scanSpans(ca, bc, ymin, ymax, scanLine); +} +TileCoord.cover = function (z, bounds, actualZ) { + var tiles = 1 << z; + var t = {}; + function scanLine(x0, x1, y) { + var x, wx, coord; + if (y >= 0 && y <= tiles) { + for (x = x0; x < x1; x++) { + wx = (x % tiles + tiles) % tiles; + coord = new TileCoord(actualZ, wx, y, Math.floor(x / tiles)); + t[coord.id] = coord; + } } - - var first = inertia[0], - last = inertia[inertia.length - 1], - previous = inertia[inertia.length - 2], - bearing = map._normalizeBearing(mapBearing, previous[1]), - flingDiff = last[1] - first[1], - sign = flingDiff < 0 ? -1 : 1, - flingDuration = (last[0] - first[0]) / 1000; - - if (flingDiff === 0 || flingDuration === 0) { - finish(); + } + scanTriangle(bounds[0], bounds[1], bounds[2], 0, tiles, scanLine); + scanTriangle(bounds[2], bounds[3], bounds[0], 0, tiles, scanLine); + return Object.keys(t).map(function (id) { + return t[id]; + }); +}; +},{"../geo/coordinate":81,"whoots-js":223}],114:[function(require,module,exports){ +'use strict'; +var Evented = require('../util/evented'); +var util = require('../util/util'); +var loadTileJSON = require('./load_tilejson'); +var normalizeURL = require('../util/mapbox').normalizeTileURL; +module.exports = VectorTileSource; +function VectorTileSource(id, options, dispatcher) { + this.id = id; + this.dispatcher = dispatcher; + util.extend(this, util.pick(options, [ + 'url', + 'scheme', + 'tileSize' + ])); + this._options = util.extend({ type: 'vector' }, options); + if (this.tileSize !== 512) { + throw new Error('vector tile sources must have a tileSize of 512'); + } + loadTileJSON(options, function (err, tileJSON) { + if (err) { + this.fire('error', err); return; } - - var speed = Math.abs(flingDiff * (inertiaLinearity / flingDuration)); // deg/s - if (speed > inertiaMaxSpeed) { - speed = inertiaMaxSpeed; - } - - var duration = speed / (inertiaDeceleration * inertiaLinearity), - offset = sign * speed * (duration / 2); - - bearing += offset; - - if (Math.abs(map._normalizeBearing(bearing, 0)) < map.options.bearingSnap) { - bearing = map._normalizeBearing(0, bearing); - } - - map.rotateTo(bearing, { - duration: duration * 1000, - easing: inertiaEasing, - noMoveStart: true - }, { originalEvent: e }); + util.extend(this, tileJSON); + this.fire('data', { dataType: 'source' }); + this.fire('source.load'); + }.bind(this)); +} +VectorTileSource.prototype = util.inherit(Evented, { + minzoom: 0, + maxzoom: 22, + scheme: 'xyz', + tileSize: 512, + reparseOverscaled: true, + isTileClipped: true, + onAdd: function (map) { + this.map = map; }, - - _fireEvent: function (type, e) { - return this._map.fire(type, { originalEvent: e }); + serialize: function () { + return util.extend({}, this._options); }, - - _ignoreEvent: function (e) { - var map = this._map; - - if (map.boxZoom && map.boxZoom.active) return true; - if (map.dragPan && map.dragPan.active) return true; - if (e.touches) { - return (e.touches.length > 1); + loadTile: function (tile, callback) { + var overscaling = tile.coord.z > this.maxzoom ? Math.pow(2, tile.coord.z - this.maxzoom) : 1; + var params = { + url: normalizeURL(tile.coord.url(this.tiles, this.maxzoom, this.scheme), this.url), + uid: tile.uid, + coord: tile.coord, + zoom: tile.coord.z, + tileSize: this.tileSize * overscaling, + source: this.id, + overscaling: overscaling, + angle: this.map.transform.angle, + pitch: this.map.transform.pitch, + showCollisionBoxes: this.map.showCollisionBoxes + }; + if (!tile.workerID) { + tile.workerID = this.dispatcher.send('load tile', params, done.bind(this)); + } else if (tile.state === 'loading') { + tile.reloadCallback = callback; } else { - var buttons = (e.ctrlKey ? 1 : 2), // ? ctrl+left button : right button - button = (e.ctrlKey ? 0 : 2); // ? ctrl+left button : right button - return (e.type === 'mousemove' ? e.buttons & buttons === 0 : e.button !== button); + this.dispatcher.send('reload tile', params, done.bind(this), tile.workerID); + } + function done(err, data) { + if (tile.aborted) + return; + if (err) { + return callback(err); + } + tile.loadVectorData(data, this.map.painter); + if (tile.redoWhenDone) { + tile.redoWhenDone = false; + tile.redoPlacement(this); + } + callback(null); + if (tile.reloadCallback) { + this.loadTile(tile, tile.reloadCallback); + tile.reloadCallback = null; + } } }, - - _drainInertiaBuffer: function () { - var inertia = this._inertia, - now = Date.now(), - cutoff = 160; //msec - - while (inertia.length > 0 && now - inertia[0][0] > cutoff) - inertia.shift(); + abortTile: function (tile) { + this.dispatcher.send('abort tile', { + uid: tile.uid, + source: this.id + }, null, tile.workerID); + }, + unloadTile: function (tile) { + tile.unloadVectorData(this.map.painter); + this.dispatcher.send('remove tile', { + uid: tile.uid, + source: this.id + }, null, tile.workerID); } - -}; - - -/** - * Rotate start event. This event is emitted at the start of a user-initiated rotate interaction. - * - * @event rotatestart - * @memberof Map - * @instance - * @property {EventData} data Original event data - */ - -/** - * Rotate event. This event is emitted repeatedly during a user-initiated rotate interaction. - * - * @event rotate - * @memberof Map - * @instance - * @property {EventData} data Original event data - */ - -/** - * Rotate end event. This event is emitted at the end of a user-initiated rotate interaction. - * - * @event rotateend - * @memberof Map - * @instance - * @property {EventData} data Original event data - */ - -},{"../../util/dom":105,"../../util/util":113,"point-geometry":162}],93:[function(require,module,exports){ +}); +},{"../util/evented":179,"../util/mapbox":185,"../util/util":188,"./load_tilejson":106}],115:[function(require,module,exports){ 'use strict'; - -module.exports = KeyboardHandler; - - -var panDelta = 80, - rotateDelta = 2, - pitchDelta = 5; - -/** - * The `KeyboardHandler` allows a user to zoom, rotate, and pan the map using - * following keyboard shortcuts: - * * `=` / `+`: increase zoom level by 1 - * * `Shift-=` / `Shift-+`: increase zoom level by 2 - * * `-`: decrease zoom level by 1 - * * `Shift--`: decrease zoom level by 2 - * * Arrow keys: pan by 80 pixels - * * `Shift+⇢`: increase rotation by 2 degrees - * * `Shift+⇠`: decrease rotation by 2 degrees - * * `Shift+⇡`: increase pitch by 5 degrees - * * `Shift+⇣`: decrease pitch by 5 degrees - * @class KeyboardHandler - */ -function KeyboardHandler(map) { - this._map = map; - this._el = map.getCanvasContainer(); - - this._onKeyDown = this._onKeyDown.bind(this); +var ajax = require('../util/ajax'); +var vt = require('vector-tile'); +var Protobuf = require('pbf'); +var WorkerTile = require('./worker_tile'); +var util = require('../util/util'); +module.exports = VectorTileWorkerSource; +function VectorTileWorkerSource(actor, styleLayers, loadVectorData) { + this.actor = actor; + this.styleLayers = styleLayers; + if (loadVectorData) { + this.loadVectorData = loadVectorData; + } + this.loading = {}; + this.loaded = {}; } - -KeyboardHandler.prototype = { - - /** - * Enable the ability to interact with the map using keyboard input. - * @example - * map.keyboard.enable(); - */ - enable: function () { - this.disable(); - this._el.addEventListener('keydown', this._onKeyDown, false); +VectorTileWorkerSource.prototype = { + loadTile: function (params, callback) { + var source = params.source, uid = params.uid; + if (!this.loading[source]) + this.loading[source] = {}; + var workerTile = this.loading[source][uid] = new WorkerTile(params); + workerTile.abort = this.loadVectorData(params, done.bind(this)); + function done(err, vectorTile) { + delete this.loading[source][uid]; + if (err) + return callback(err); + if (!vectorTile) + return callback(null, null); + workerTile.vectorTile = vectorTile; + workerTile.parse(vectorTile, this.styleLayers.getLayerFamilies(), this.actor, function (err, result, transferrables) { + if (err) + return callback(err); + callback(null, util.extend({ rawTileData: vectorTile.rawData }, result), transferrables); + }); + this.loaded[source] = this.loaded[source] || {}; + this.loaded[source][uid] = workerTile; + } }, - - /** - * Disable the ability to interact with the map using keyboard input. - * @example - * map.keyboard.disable(); - */ - disable: function () { - this._el.removeEventListener('keydown', this._onKeyDown); + reloadTile: function (params, callback) { + var loaded = this.loaded[params.source], uid = params.uid; + if (loaded && loaded[uid]) { + var workerTile = loaded[uid]; + workerTile.parse(workerTile.vectorTile, this.styleLayers.getLayerFamilies(), this.actor, callback); + } }, - - _onKeyDown: function (e) { - if (e.altKey || e.ctrlKey || e.metaKey) return; - - var map = this._map, - eventData = { originalEvent: e }; - - switch (e.keyCode) { - case 61: - case 107: - case 171: - case 187: - map.zoomTo(Math.round(map.getZoom()) + (e.shiftKey ? 2 : 1), eventData); - break; - - case 189: - case 109: - case 173: - map.zoomTo(Math.round(map.getZoom()) - (e.shiftKey ? 2 : 1), eventData); - break; - - case 37: - if (e.shiftKey) { - map.easeTo({ bearing: map.getBearing() - rotateDelta }, eventData); - } else { - map.panBy([-panDelta, 0], eventData); + abortTile: function (params) { + var loading = this.loading[params.source], uid = params.uid; + if (loading && loading[uid] && loading[uid].abort) { + loading[uid].abort(); + delete loading[uid]; + } + }, + removeTile: function (params) { + var loaded = this.loaded[params.source], uid = params.uid; + if (loaded && loaded[uid]) { + delete loaded[uid]; + } + }, + loadVectorData: function (params, callback) { + var xhr = ajax.getArrayBuffer(params.url, done.bind(this)); + return function abort() { + xhr.abort(); + }; + function done(err, arrayBuffer) { + if (err) { + return callback(err); } - break; - - case 39: - if (e.shiftKey) { - map.easeTo({ bearing: map.getBearing() + rotateDelta }, eventData); - } else { - map.panBy([panDelta, 0], eventData); + var vectorTile = new vt.VectorTile(new Protobuf(arrayBuffer)); + vectorTile.rawData = arrayBuffer; + callback(err, vectorTile); + } + }, + redoPlacement: function (params, callback) { + var loaded = this.loaded[params.source], loading = this.loading[params.source], uid = params.uid; + if (loaded && loaded[uid]) { + var workerTile = loaded[uid]; + var result = workerTile.redoPlacement(params.angle, params.pitch, params.showCollisionBoxes); + if (result.result) { + callback(null, result.result, result.transferables); } - break; - - case 38: - if (e.shiftKey) { - map.easeTo({ pitch: map.getPitch() + pitchDelta }, eventData); - } else { - map.panBy([0, -panDelta], eventData); - } - break; - - case 40: - if (e.shiftKey) { - map.easeTo({ pitch: Math.max(map.getPitch() - pitchDelta, 0) }, eventData); - } else { - map.panBy([0, panDelta], eventData); - } - break; + } else if (loading && loading[uid]) { + loading[uid].angle = params.angle; } } }; - -},{}],94:[function(require,module,exports){ +},{"../util/ajax":170,"../util/util":188,"./worker_tile":118,"pbf":192,"vector-tile":212}],116:[function(require,module,exports){ 'use strict'; - -var DOM = require('../../util/dom'), - browser = require('../../util/browser'), - util = require('../../util/util'); - -module.exports = ScrollZoomHandler; - - -var ua = typeof navigator !== 'undefined' ? navigator.userAgent.toLowerCase() : '', - firefox = ua.indexOf('firefox') !== -1, - safari = ua.indexOf('safari') !== -1 && ua.indexOf('chrom') === -1; - - -/** - * The `ScrollZoomHandler` allows a user to zoom the map by scrolling. - * @class ScrollZoomHandler - */ -function ScrollZoomHandler(map) { - this._map = map; - this._el = map.getCanvasContainer(); - - util.bindHandlers(this); +var util = require('../util/util'); +var TileCoord = require('./tile_coord'); +var LngLat = require('../geo/lng_lat'); +var Point = require('point-geometry'); +var Evented = require('../util/evented'); +var ajax = require('../util/ajax'); +var EXTENT = require('../data/bucket').EXTENT; +var RasterBoundsArray = require('../render/draw_raster').RasterBoundsArray; +var Buffer = require('../data/buffer'); +var VertexArrayObject = require('../render/vertex_array_object'); +module.exports = VideoSource; +function VideoSource(id, options) { + this.id = id; + this.urls = options.urls; + this.coordinates = options.coordinates; + ajax.getVideo(options.urls, function (err, video) { + if (err) + return this.fire('error', { error: err }); + this.video = video; + this.video.loop = true; + var loopID; + this.video.addEventListener('playing', function () { + loopID = this.map.style.animationLoop.set(Infinity); + this.map._rerender(); + }.bind(this)); + this.video.addEventListener('pause', function () { + this.map.style.animationLoop.cancel(loopID); + }.bind(this)); + if (this.map) { + this.video.play(); + this.setCoordinates(options.coordinates); + } + this.fire('data', { dataType: 'source' }); + this.fire('source.load'); + }.bind(this)); } - -ScrollZoomHandler.prototype = { - - /** - * Enable the "scroll to zoom" interaction. - * @example - * map.scrollZoom.enable(); - */ - enable: function () { - this.disable(); - this._el.addEventListener('wheel', this._onWheel, false); - this._el.addEventListener('mousewheel', this._onWheel, false); - }, - - /** - * Disable the "scroll to zoom" interaction. - * @example - * map.scrollZoom.disable(); - */ - disable: function () { - this._el.removeEventListener('wheel', this._onWheel); - this._el.removeEventListener('mousewheel', this._onWheel); +VideoSource.prototype = util.inherit(Evented, { + minzoom: 0, + maxzoom: 22, + tileSize: 512, + roundZoom: true, + getVideo: function () { + return this.video; }, - - _onWheel: function (e) { - var value; - - if (e.type === 'wheel') { - value = e.deltaY; - // Firefox doubles the values on retina screens... - if (firefox && e.deltaMode === window.WheelEvent.DOM_DELTA_PIXEL) value /= browser.devicePixelRatio; - if (e.deltaMode === window.WheelEvent.DOM_DELTA_LINE) value *= 40; - - } else if (e.type === 'mousewheel') { - value = -e.wheelDeltaY; - if (safari) value = value / 3; + onAdd: function (map) { + if (this.map) + return; + this.map = map; + if (this.video) { + this.video.play(); + this.setCoordinates(this.coordinates); } - - var now = browser.now(), - timeDelta = now - (this._time || 0); - - this._pos = DOM.mousePos(this._el, e); - this._time = now; - - if (value !== 0 && (value % 4.000244140625) === 0) { - // This one is definitely a mouse wheel event. - this._type = 'wheel'; - // Normalize this value to match trackpad. - value = Math.floor(value / 4); - - } else if (value !== 0 && Math.abs(value) < 4) { - // This one is definitely a trackpad event because it is so small. - this._type = 'trackpad'; - - } else if (timeDelta > 400) { - // This is likely a new scroll action. - this._type = null; - this._lastValue = value; - - // Start a timeout in case this was a singular event, and dely it by up to 40ms. - this._timeout = setTimeout(this._onTimeout, 40); - - } else if (!this._type) { - // This is a repeating event, but we don't know the type of event just yet. - // If the delta per time is small, we assume it's a fast trackpad; otherwise we switch into wheel mode. - this._type = (Math.abs(timeDelta * value) < 200) ? 'trackpad' : 'wheel'; - - // Make sure our delayed event isn't fired again, because we accumulate - // the previous event (which was less than 40ms ago) into this event. - if (this._timeout) { - clearTimeout(this._timeout); - this._timeout = null; - value += this._lastValue; - } + }, + setCoordinates: function (coordinates) { + this.coordinates = coordinates; + var map = this.map; + var cornerZ0Coords = coordinates.map(function (coord) { + return map.transform.locationCoordinate(LngLat.convert(coord)).zoomTo(0); + }); + var centerCoord = this.centerCoord = util.getCoordinatesCenter(cornerZ0Coords); + centerCoord.column = Math.round(centerCoord.column); + centerCoord.row = Math.round(centerCoord.row); + this.minzoom = this.maxzoom = centerCoord.zoom; + this.coord = new TileCoord(centerCoord.zoom, centerCoord.column, centerCoord.row); + this._tileCoords = cornerZ0Coords.map(function (coord) { + var zoomedCoord = coord.zoomTo(centerCoord.zoom); + return new Point(Math.round((zoomedCoord.column - centerCoord.column) * EXTENT), Math.round((zoomedCoord.row - centerCoord.row) * EXTENT)); + }); + this.fire('data', { dataType: 'source' }); + return this; + }, + _setTile: function (tile) { + this._prepared = false; + this.tile = tile; + var maxInt16 = 32767; + var array = new RasterBoundsArray(); + array.emplaceBack(this._tileCoords[0].x, this._tileCoords[0].y, 0, 0); + array.emplaceBack(this._tileCoords[1].x, this._tileCoords[1].y, maxInt16, 0); + array.emplaceBack(this._tileCoords[3].x, this._tileCoords[3].y, 0, maxInt16); + array.emplaceBack(this._tileCoords[2].x, this._tileCoords[2].y, maxInt16, maxInt16); + this.tile.buckets = {}; + this.tile.boundsBuffer = new Buffer(array.serialize(), RasterBoundsArray.serialize(), Buffer.BufferType.VERTEX); + this.tile.boundsVAO = new VertexArrayObject(); + this.tile.state = 'loaded'; + }, + prepare: function () { + if (this.video.readyState < 2) + return; + if (!this.tile) + return; + var gl = this.map.painter.gl; + if (!this._prepared) { + this._prepared = true; + this.tile.texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this.tile.texture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.video); + } else { + gl.bindTexture(gl.TEXTURE_2D, this.tile.texture); + gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.video); } - - // Slow down zoom if shift key is held for more precise zooming - if (e.shiftKey && value) value = value / 4; - - // Only fire the callback if we actually know what type of scrolling device the user uses. - if (this._type) this._zoom(-value, e); - - e.preventDefault(); + this._currentTime = this.video.currentTime; }, - - _onTimeout: function () { - this._type = 'wheel'; - this._zoom(-this._lastValue); + loadTile: function (tile, callback) { + if (this.coord && this.coord.toString() === tile.coord.toString()) { + this._setTile(tile); + callback(null); + } else { + tile.state = 'errored'; + callback(null); + } }, - - _zoom: function (delta, e) { - if (delta === 0) return; - var map = this._map; - - // Scale by sigmoid of scroll wheel delta. - var scale = 2 / (1 + Math.exp(-Math.abs(delta / 100))); - if (delta < 0 && scale !== 0) scale = 1 / scale; - - var fromScale = map.ease ? map.ease.to : map.transform.scale, - targetZoom = map.transform.scaleZoom(fromScale * scale); - - map.zoomTo(targetZoom, { - duration: 0, - around: map.unproject(this._pos) - }, { originalEvent: e }); + serialize: function () { + return { + type: 'video', + urls: this.urls, + coordinates: this.coordinates + }; } -}; - - -/** - * Zoom start event. This event is emitted just before the map begins a transition from one - * zoom level to another, either as a result of user interaction or the use of methods such as `Map#jumpTo`. - * - * @event zoomstart - * @memberof Map - * @instance - * @property {EventData} data Original event data, if fired interactively - */ - -/** - * Zoom event. This event is emitted repeatedly during animated transitions from one zoom level to - * another, either as a result of user interaction or the use of methods such as `Map#jumpTo`. - * - * @event zoom - * @memberof Map - * @instance - * @property {EventData} data Original event data, if fired interactively - */ - -/** - * Zoom end event. This event is emitted just after the map completes a transition from one - * zoom level to another, either as a result of user interaction or the use of methods such as `Map#jumpTo`. - * - * @event zoomend - * @memberof Map - * @instance - * @property {EventData} data Original event data, if fired interactively - */ - -},{"../../util/browser":102,"../../util/dom":105,"../../util/util":113}],95:[function(require,module,exports){ +}); +},{"../data/bucket":72,"../data/buffer":77,"../geo/lng_lat":82,"../render/draw_raster":95,"../render/vertex_array_object":101,"../util/ajax":170,"../util/evented":179,"../util/util":188,"./tile_coord":113,"point-geometry":196}],117:[function(require,module,exports){ 'use strict'; - -var DOM = require('../../util/dom'), - util = require('../../util/util'); - -module.exports = TouchZoomRotateHandler; - -var inertiaLinearity = 0.15, - inertiaEasing = util.bezier(0, 0, inertiaLinearity, 1), - inertiaDeceleration = 12, // scale / s^2 - inertiaMaxSpeed = 2.5, // scale / s - significantScaleThreshold = 0.15, - significantRotateThreshold = 4; - - -/** - * The `TouchZoomRotateHandler` allows a user to zoom and rotate the map by - * pinching on a touchscreen. - * @class TouchZoomRotateHandler - */ -function TouchZoomRotateHandler(map) { - this._map = map; - this._el = map.getCanvasContainer(); - - util.bindHandlers(this); +var Actor = require('../util/actor'); +var StyleLayer = require('../style/style_layer'); +var util = require('../util/util'); +var VectorTileWorkerSource = require('./vector_tile_worker_source'); +var GeoJSONWorkerSource = require('./geojson_worker_source'); +var featureFilter = require('feature-filter'); +module.exports = function createWorker(self) { + return new Worker(self); +}; +function Worker(self) { + this.self = self; + this.actor = new Actor(self, this); + this.layers = {}; + this.layerFamilies = {}; + this.workerSourceTypes = { + vector: VectorTileWorkerSource, + geojson: GeoJSONWorkerSource + }; + this.workerSources = {}; + this.self.registerWorkerSource = function (name, WorkerSource) { + if (this.workerSourceTypes[name]) { + throw new Error('Worker source with name "' + name + '" already registered.'); + } + this.workerSourceTypes[name] = WorkerSource; + }.bind(this); } - -TouchZoomRotateHandler.prototype = { - - /** - * Enable the "pinch to rotate and zoom" interaction. - * @example - * map.touchZoomRotate.enable(); - */ - enable: function () { - this.disable(); - this._el.addEventListener('touchstart', this._onStart, false); +util.extend(Worker.prototype, { + 'set layers': function (mapId, layerDefinitions) { + var layers = this.layers[mapId] = {}; + var childLayerIndicies = []; + for (var i = 0; i < layerDefinitions.length; i++) { + var layer = layerDefinitions[i]; + if (layer.type === 'fill' || layer.type === 'line' || layer.type === 'circle' || layer.type === 'symbol') { + if (layer.ref) { + childLayerIndicies.push(i); + } else { + setLayer(layer); + } + } + } + for (var j = 0; j < childLayerIndicies.length; j++) { + setLayer(layerDefinitions[childLayerIndicies[j]]); + } + function setLayer(serializedLayer) { + var styleLayer = StyleLayer.create(serializedLayer, serializedLayer.ref && layers[serializedLayer.ref]); + styleLayer.updatePaintTransitions({}, { transition: false }); + styleLayer.filter = featureFilter(styleLayer.filter); + layers[styleLayer.id] = styleLayer; + } + this.layerFamilies[mapId] = createLayerFamilies(this.layers[mapId]); + }, + 'update layers': function (mapId, layerDefinitions) { + var id; + var layer; + var layers = this.layers[mapId]; + for (id in layerDefinitions) { + layer = layerDefinitions[id]; + if (layer.ref) + updateLayer(layer); + } + for (id in layerDefinitions) { + layer = layerDefinitions[id]; + if (!layer.ref) + updateLayer(layer); + } + function updateLayer(layer) { + var refLayer = layers[layer.ref]; + var styleLayer = layers[layer.id]; + if (styleLayer) { + styleLayer.set(layer, refLayer); + } else { + styleLayer = layers[layer.id] = StyleLayer.create(layer, refLayer); + } + styleLayer.updatePaintTransitions({}, { transition: false }); + styleLayer.filter = featureFilter(styleLayer.filter); + } + this.layerFamilies[mapId] = createLayerFamilies(this.layers[mapId]); }, - - /** - * Disable the "pinch to rotate and zoom" interaction. - * @example - * map.touchZoomRotate.disable(); - */ - disable: function () { - this._el.removeEventListener('touchstart', this._onStart); + 'load tile': function (mapId, params, callback) { + var type = params.type || 'vector'; + this.getWorkerSource(mapId, type).loadTile(params, callback); }, - - /** - * Disable the "pinch to rotate" interaction, leaving the "pinch to zoom" - * interaction enabled. - * @example - * map.touchZoomRotate.disableRotation(); - */ - disableRotation: function() { - this._rotationDisabled = true; + 'reload tile': function (mapId, params, callback) { + var type = params.type || 'vector'; + this.getWorkerSource(mapId, type).reloadTile(params, callback); }, - - /** - * Enable the "pinch to rotate" interaction, undoing a call to - * `disableRotation`. - * @example - * map.touchZoomRotate.enable(); - * map.touchZoomRotate.enableRotation(); - */ - enableRotation: function() { - this._rotationDisabled = false; + 'abort tile': function (mapId, params) { + var type = params.type || 'vector'; + this.getWorkerSource(mapId, type).abortTile(params); }, - - _onStart: function (e) { - if (e.touches.length !== 2) return; - - var p0 = DOM.mousePos(this._el, e.touches[0]), - p1 = DOM.mousePos(this._el, e.touches[1]); - - this._startVec = p0.sub(p1); - this._startScale = this._map.transform.scale; - this._startBearing = this._map.transform.bearing; - this._gestureIntent = undefined; - this._inertia = []; - - document.addEventListener('touchmove', this._onMove, false); - document.addEventListener('touchend', this._onEnd, false); + 'remove tile': function (mapId, params) { + var type = params.type || 'vector'; + this.getWorkerSource(mapId, type).removeTile(params); }, - - _onMove: function (e) { - if (e.touches.length !== 2) return; - - var p0 = DOM.mousePos(this._el, e.touches[0]), - p1 = DOM.mousePos(this._el, e.touches[1]), - p = p0.add(p1).div(2), - vec = p0.sub(p1), - scale = vec.mag() / this._startVec.mag(), - bearing = this._rotationDisabled ? 0 : vec.angleWith(this._startVec) * 180 / Math.PI, - map = this._map; - - // Determine 'intent' by whichever threshold is surpassed first, - // then keep that state for the duration of this gesture. - if (!this._gestureIntent) { - var scalingSignificantly = (Math.abs(1 - scale) > significantScaleThreshold), - rotatingSignificantly = (Math.abs(bearing) > significantRotateThreshold); - - if (rotatingSignificantly) { - this._gestureIntent = 'rotate'; - } else if (scalingSignificantly) { - this._gestureIntent = 'zoom'; - } - - if (this._gestureIntent) { - this._startVec = vec; - this._startScale = map.transform.scale; - this._startBearing = map.transform.bearing; - } - + 'redo placement': function (mapId, params, callback) { + var type = params.type || 'vector'; + this.getWorkerSource(mapId, type).redoPlacement(params, callback); + }, + 'load worker source': function (map, params, callback) { + try { + this.self.importScripts(params.url); + callback(); + } catch (e) { + callback(e); + } + }, + getWorkerSource: function (mapId, type) { + if (!this.workerSources[mapId]) + this.workerSources[mapId] = {}; + if (!this.workerSources[mapId][type]) { + var layers = { + getLayers: function () { + return this.layers[mapId]; + }.bind(this), + getLayerFamilies: function () { + return this.layerFamilies[mapId]; + }.bind(this) + }; + var actor = { + send: function (type, data, callback, buffers) { + this.actor.send(type, data, callback, buffers, mapId); + }.bind(this) + }; + this.workerSources[mapId][type] = new this.workerSourceTypes[type](actor, layers); + } + return this.workerSources[mapId][type]; + } +}); +function createLayerFamilies(layers) { + var families = {}; + for (var layerId in layers) { + var layer = layers[layerId]; + var parentLayerId = layer.ref || layer.id; + var parentLayer = layers[parentLayerId]; + if (parentLayer.layout && parentLayer.layout.visibility === 'none') + continue; + families[parentLayerId] = families[parentLayerId] || []; + if (layerId === parentLayerId) { + families[parentLayerId].unshift(layer); } else { - var param = { duration: 0, around: map.unproject(p) }; - - if (this._gestureIntent === 'rotate') { - param.bearing = this._startBearing + bearing; - } - if (this._gestureIntent === 'zoom' || this._gestureIntent === 'rotate') { - param.zoom = map.transform.scaleZoom(this._startScale * scale); - } - - map.stop(); - this._drainInertiaBuffer(); - this._inertia.push([Date.now(), scale, p]); - - map.easeTo(param, { originalEvent: e }); - } - - e.preventDefault(); - }, - - _onEnd: function (e) { - document.removeEventListener('touchmove', this._onMove); - document.removeEventListener('touchend', this._onEnd); - this._drainInertiaBuffer(); - - var inertia = this._inertia, - map = this._map; - - if (inertia.length < 2) { - map.snapToNorth({}, { originalEvent: e }); - return; - } - - var last = inertia[inertia.length - 1], - first = inertia[0], - lastScale = map.transform.scaleZoom(this._startScale * last[1]), - firstScale = map.transform.scaleZoom(this._startScale * first[1]), - scaleOffset = lastScale - firstScale, - scaleDuration = (last[0] - first[0]) / 1000, - p = last[2]; - - if (scaleDuration === 0 || lastScale === firstScale) { - map.snapToNorth({}, { originalEvent: e }); - return; - } - - // calculate scale/s speed and adjust for increased initial animation speed when easing - var speed = scaleOffset * inertiaLinearity / scaleDuration; // scale/s - - if (Math.abs(speed) > inertiaMaxSpeed) { - if (speed > 0) { - speed = inertiaMaxSpeed; - } else { - speed = -inertiaMaxSpeed; - } + families[parentLayerId].push(layer); } - - var duration = Math.abs(speed / (inertiaDeceleration * inertiaLinearity)) * 1000, - targetScale = lastScale + speed * duration / 2000; - - if (targetScale < 0) { - targetScale = 0; - } - - map.easeTo({ - zoom: targetScale, - duration: duration, - easing: inertiaEasing, - around: map.unproject(p) - }, { originalEvent: e }); - }, - - _drainInertiaBuffer: function() { - var inertia = this._inertia, - now = Date.now(), - cutoff = 160; // msec - - while (inertia.length > 2 && now - inertia[0][0] > cutoff) inertia.shift(); } -}; - -},{"../../util/dom":105,"../../util/util":113}],96:[function(require,module,exports){ + return families; +} +},{"../style/style_layer":125,"../util/actor":169,"../util/util":188,"./geojson_worker_source":103,"./vector_tile_worker_source":115,"feature-filter":12}],118:[function(require,module,exports){ 'use strict'; - -/* - * Adds positional coordinates to URL hashes. Passed as an option to the map object - * - * @class mapboxgl.Hash - * @returns {Hash} `this` - */ -module.exports = Hash; - +var FeatureIndex = require('../data/feature_index'); +var CollisionTile = require('../symbol/collision_tile'); +var Bucket = require('../data/bucket'); +var CollisionBoxArray = require('../symbol/collision_box'); +var DictionaryCoder = require('../util/dictionary_coder'); var util = require('../util/util'); - -function Hash() { - util.bindAll([ - '_onHashChange', - '_updateHash' - ], this); +var SymbolInstancesArray = require('../symbol/symbol_instances'); +var SymbolQuadsArray = require('../symbol/symbol_quads'); +module.exports = WorkerTile; +function WorkerTile(params) { + this.coord = params.coord; + this.uid = params.uid; + this.zoom = params.zoom; + this.tileSize = params.tileSize; + this.source = params.source; + this.overscaling = params.overscaling; + this.angle = params.angle; + this.pitch = params.pitch; + this.showCollisionBoxes = params.showCollisionBoxes; } - -Hash.prototype = { - /* Map element to listen for coordinate changes - * - * @param {Object} map - * @returns {Hash} `this` - */ - addTo: function(map) { - this._map = map; - window.addEventListener('hashchange', this._onHashChange, false); - this._map.on('moveend', this._updateHash); - return this; - }, - - /* Removes hash - * - * @returns {Popup} `this` - */ - remove: function() { - window.removeEventListener('hashchange', this._onHashChange, false); - this._map.off('moveend', this._updateHash); - delete this._map; - return this; - }, - - _onHashChange: function() { - var loc = location.hash.replace('#', '').split('/'); - if (loc.length >= 3) { - this._map.jumpTo({ - center: [+loc[2], +loc[1]], - zoom: +loc[0], - bearing: +(loc[3] || 0) - }); - return true; +WorkerTile.prototype.parse = function (data, layerFamilies, actor, callback) { + this.status = 'parsing'; + this.data = data; + this.collisionBoxArray = new CollisionBoxArray(); + this.symbolInstancesArray = new SymbolInstancesArray(); + this.symbolQuadsArray = new SymbolQuadsArray(); + var collisionTile = new CollisionTile(this.angle, this.pitch, this.collisionBoxArray); + var featureIndex = new FeatureIndex(this.coord, this.overscaling, collisionTile, data.layers); + var sourceLayerCoder = new DictionaryCoder(data.layers ? Object.keys(data.layers).sort() : ['_geojsonTileLayer']); + var tile = this; + var bucketsById = {}; + var bucketsBySourceLayer = {}; + var i; + var layer; + var sourceLayerId; + var bucket; + var bucketIndex = 0; + for (var layerId in layerFamilies) { + layer = layerFamilies[layerId][0]; + if (layer.source !== this.source) + continue; + if (layer.ref) + continue; + if (layer.minzoom && this.zoom < layer.minzoom) + continue; + if (layer.maxzoom && this.zoom >= layer.maxzoom) + continue; + if (layer.layout && layer.layout.visibility === 'none') + continue; + if (data.layers && !data.layers[layer.sourceLayer]) + continue; + bucket = Bucket.create({ + layer: layer, + index: bucketIndex++, + childLayers: layerFamilies[layerId], + zoom: this.zoom, + overscaling: this.overscaling, + showCollisionBoxes: this.showCollisionBoxes, + collisionBoxArray: this.collisionBoxArray, + symbolQuadsArray: this.symbolQuadsArray, + symbolInstancesArray: this.symbolInstancesArray, + sourceLayerIndex: sourceLayerCoder.encode(layer.sourceLayer || '_geojsonTileLayer') + }); + bucketsById[layer.id] = bucket; + if (data.layers) { + sourceLayerId = layer.sourceLayer; + bucketsBySourceLayer[sourceLayerId] = bucketsBySourceLayer[sourceLayerId] || {}; + bucketsBySourceLayer[sourceLayerId][layer.id] = bucket; } - return false; - }, - - _updateHash: function() { - var center = this._map.getCenter(), - zoom = this._map.getZoom(), - bearing = this._map.getBearing(), - precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2)), - - hash = '#' + (Math.round(zoom * 100) / 100) + - '/' + center.lat.toFixed(precision) + - '/' + center.lng.toFixed(precision) + - (bearing ? '/' + (Math.round(bearing * 10) / 10) : ''); - - window.history.replaceState('', '', hash); } -}; - -},{"../util/util":113}],97:[function(require,module,exports){ -'use strict'; - -var handlers = { - scrollZoom: require('./handler/scroll_zoom'), - boxZoom: require('./handler/box_zoom'), - dragRotate: require('./handler/drag_rotate'), - dragPan: require('./handler/drag_pan'), - keyboard: require('./handler/keyboard'), - doubleClickZoom: require('./handler/dblclick_zoom'), - touchZoomRotate: require('./handler/touch_zoom_rotate') -}; - -var DOM = require('../util/dom'), - util = require('../util/util'); - -module.exports = Interaction; - -function Interaction(map) { - this._map = map; - this._el = map.getCanvasContainer(); - - for (var name in handlers) { - map[name] = new handlers[name](map); + if (data.layers) { + for (sourceLayerId in bucketsBySourceLayer) { + if (layer.version === 1) { + util.warnOnce('Vector tile source "' + this.source + '" layer "' + sourceLayerId + '" does not use vector tile spec v2 ' + 'and therefore may have some rendering errors.'); + } + layer = data.layers[sourceLayerId]; + if (layer) { + sortLayerIntoBuckets(layer, bucketsBySourceLayer[sourceLayerId]); + } + } + } else { + sortLayerIntoBuckets(data, bucketsById); } - - util.bindHandlers(this); -} - -Interaction.prototype = { - enable: function () { - var options = this._map.options, - el = this._el; - - for (var name in handlers) { - if (options[name]) this._map[name].enable(); + function sortLayerIntoBuckets(layer, buckets) { + for (var i = 0; i < layer.length; i++) { + var feature = layer.feature(i); + feature.index = i; + for (var id in buckets) { + if (buckets[id].layer.filter(feature)) + buckets[id].features.push(feature); + } } - - el.addEventListener('mousedown', this._onMouseDown, false); - el.addEventListener('mouseup', this._onMouseUp, false); - el.addEventListener('touchstart', this._onTouchStart, false); - el.addEventListener('click', this._onClick, false); - el.addEventListener('mousemove', this._onMouseMove, false); - el.addEventListener('dblclick', this._onDblClick, false); - el.addEventListener('contextmenu', this._onContextMenu, false); - }, - - disable: function () { - var options = this._map.options, - el = this._el; - - for (var name in handlers) { - if (options[name]) this._map[name].disable(); + } + var buckets = [], symbolBuckets = this.symbolBuckets = [], otherBuckets = []; + featureIndex.bucketLayerIDs = {}; + for (var id in bucketsById) { + bucket = bucketsById[id]; + if (bucket.features.length === 0) + continue; + featureIndex.bucketLayerIDs[bucket.index] = bucket.childLayers.map(getLayerId); + buckets.push(bucket); + if (bucket.type === 'symbol') + symbolBuckets.push(bucket); + else + otherBuckets.push(bucket); + } + var icons = {}; + var stacks = {}; + var deps = 0; + if (symbolBuckets.length > 0) { + for (i = symbolBuckets.length - 1; i >= 0; i--) { + symbolBuckets[i].updateIcons(icons); + symbolBuckets[i].updateFont(stacks); } - - el.removeEventListener('mousedown', this._onMouseDown); - el.removeEventListener('mouseup', this._onMouseUp); - el.removeEventListener('touchstart', this._onTouchStart); - el.removeEventListener('click', this._onClick); - el.removeEventListener('mousemove', this._onMouseMove); - el.removeEventListener('dblclick', this._onDblClick); - el.removeEventListener('contextmenu', this._onContextMenu); - }, - - _onMouseDown: function (e) { - this._map.stop(); - this._startPos = DOM.mousePos(this._el, e); - this._fireEvent('mousedown', e); - }, - - _onMouseUp: function (e) { - var map = this._map, - rotating = map.dragRotate && map.dragRotate.active; - - if (this._contextMenuEvent && !rotating) { - this._fireEvent('contextmenu', this._contextMenuEvent); + for (var fontName in stacks) { + stacks[fontName] = Object.keys(stacks[fontName]).map(Number); } - - this._contextMenuEvent = null; - this._fireEvent('mouseup', e); - }, - - _onTouchStart: function (e) { - if (!e.touches || e.touches.length > 1) return; - - if (!this._tapped) { - this._tapped = setTimeout(this._onTimeout, 300); - + icons = Object.keys(icons); + actor.send('get glyphs', { + uid: this.uid, + stacks: stacks + }, function (err, newStacks) { + stacks = newStacks; + gotDependency(err); + }); + if (icons.length) { + actor.send('get icons', { icons: icons }, function (err, newIcons) { + icons = newIcons; + gotDependency(err); + }); } else { - clearTimeout(this._tapped); - this._tapped = null; - this._fireEvent('dblclick', e); + gotDependency(); } - }, - - _onTimeout: function () { - this._tapped = null; - }, - - _onMouseMove: function (e) { - var map = this._map, - el = this._el; - - if (map.dragPan && map.dragPan.active) return; - if (map.dragRotate && map.dragRotate.active) return; - - var target = e.toElement || e.target; - while (target && target !== el) target = target.parentNode; - if (target !== el) return; - - this._fireEvent('mousemove', e); - }, - - _onClick: function (e) { - var pos = DOM.mousePos(this._el, e); - - if (pos.equals(this._startPos)) { - this._fireEvent('click', e); + } + for (i = otherBuckets.length - 1; i >= 0; i--) { + parseBucket(this, otherBuckets[i]); + } + if (symbolBuckets.length === 0) + return done(); + function gotDependency(err) { + if (err) + return callback(err); + deps++; + if (deps === 2) { + for (var i = symbolBuckets.length - 1; i >= 0; i--) { + parseBucket(tile, symbolBuckets[i]); + } + done(); } - }, - - _onDblClick: function (e) { - this._fireEvent('dblclick', e); - e.preventDefault(); - }, - - _onContextMenu: function (e) { - this._contextMenuEvent = e; - e.preventDefault(); - }, - - _fireEvent: function (type, e) { - var pos = DOM.mousePos(this._el, e); - - return this._map.fire(type, { - lngLat: this._map.unproject(pos), - point: pos, - originalEvent: e - }); + } + function parseBucket(tile, bucket) { + bucket.populateArrays(collisionTile, stacks, icons); + if (bucket.type !== 'symbol') { + for (var i = 0; i < bucket.features.length; i++) { + var feature = bucket.features[i]; + featureIndex.insert(feature, feature.index, bucket.sourceLayerIndex, bucket.index); + } + } + bucket.features = null; + } + function done() { + tile.status = 'done'; + if (tile.redoPlacementAfterDone) { + tile.redoPlacement(tile.angle, tile.pitch, null); + tile.redoPlacementAfterDone = false; + } + var featureIndex_ = featureIndex.serialize(); + var collisionTile_ = collisionTile.serialize(); + var collisionBoxArray = tile.collisionBoxArray.serialize(); + var symbolInstancesArray = tile.symbolInstancesArray.serialize(); + var symbolQuadsArray = tile.symbolQuadsArray.serialize(); + var nonEmptyBuckets = buckets.filter(isBucketNonEmpty); + callback(null, { + buckets: nonEmptyBuckets.map(serializeBucket), + featureIndex: featureIndex_.data, + collisionTile: collisionTile_.data, + collisionBoxArray: collisionBoxArray, + symbolInstancesArray: symbolInstancesArray, + symbolQuadsArray: symbolQuadsArray + }, getTransferables(nonEmptyBuckets).concat(featureIndex_.transferables).concat(collisionTile_.transferables)); } }; - - -/** - * When an event [fires]{@link #Evented.fire} as a result of a - * user interaction, the event will be called with an EventData - * object containing the original DOM event along with coordinates of - * the event target. - * - * @typedef {Object} EventData - * @property {Event} originalEvent The original DOM event - * @property {Point} point The pixel location of the event - * @property {LngLat} lngLat The geographic location of the event - * @example - * map.on('click', function(data) { - * var e = data && data.originalEvent; - * console.log('got click ' + (e ? 'button = ' + e.button : '')); - * }); - */ - -/** - * Mouse down event. - * - * @event mousedown - * @memberof Map - * @instance - * @property {EventData} data Original event data - */ - -/** - * Mouse up event. - * - * @event mouseup - * @memberof Map - * @instance - * @property {EventData} data Original event data - */ - -/** - * Mouse move event. - * - * @event mousemove - * @memberof Map - * @instance - * @property {EventData} data Original event data - */ - -/** - * Click event. - * - * @event click - * @memberof Map - * @instance - * @property {EventData} data Original event data - */ - -/** - * Double click event. - * - * @event dblclick - * @memberof Map - * @instance - * @property {EventData} data Original event data - */ - -/** - * Context menu event. - * - * @event contextmenu - * @memberof Map - * @instance - * @property {EventData} data Original event data, if available - */ - -/** - * Load event. This event is emitted immediately after all necessary resources have been downloaded - * and the first visually complete rendering has occurred. - * - * @event load - * @memberof Map - * @instance - * @type {Object} - */ - -/** - * Move start event. This event is emitted just before the map begins a transition from one - * view to another, either as a result of user interaction or the use of methods such as `Map#jumpTo`. - * - * @event movestart - * @memberof Map - * @instance - * @property {EventData} data Original event data, if fired interactively - */ - -/** - * Move event. This event is emitted repeatedly during animated transitions from one view to - * another, either as a result of user interaction or the use of methods such as `Map#jumpTo`. - * - * @event move - * @memberof Map - * @instance - * @property {EventData} data Original event data, if fired interactively - */ - -/** - * Move end event. This event is emitted just after the map completes a transition from one - * view to another, either as a result of user interaction or the use of methods such as `Map#jumpTo`. - * - * @event moveend - * @memberof Map - * @instance - * @property {EventData} data Original event data, if fired interactively - */ - -},{"../util/dom":105,"../util/util":113,"./handler/box_zoom":89,"./handler/dblclick_zoom":90,"./handler/drag_pan":91,"./handler/drag_rotate":92,"./handler/keyboard":93,"./handler/scroll_zoom":94,"./handler/touch_zoom_rotate":95}],98:[function(require,module,exports){ -'use strict'; - -var Canvas = require('../util/canvas'); -var util = require('../util/util'); -var browser = require('../util/browser'); -var Evented = require('../util/evented'); -var DOM = require('../util/dom'); - -var Style = require('../style/style'); -var AnimationLoop = require('../style/animation_loop'); -var Painter = require('../render/painter'); - -var Transform = require('../geo/transform'); -var Hash = require('./hash'); - -var Interaction = require('./interaction'); - -var Camera = require('./camera'); -var LngLat = require('../geo/lng_lat'); -var LngLatBounds = require('../geo/lng_lat_bounds'); -var Point = require('point-geometry'); -var Attribution = require('./control/attribution'); - -/** - * Options common to Map#addClass, Map#removeClass, and Map#setClasses, controlling - * whether or not to smoothly transition property changes triggered by the class change. - * - * @typedef {Object} StyleOptions - * @property {boolean} transition - */ - -/** - * Creates a map instance. - * @class Map - * @param {Object} options - * @param {string|Element} options.container HTML element to initialize the map in (or element id as string) - * @param {number} [options.minZoom=0] Minimum zoom of the map - * @param {number} [options.maxZoom=20] Maximum zoom of the map - * @param {Object|string} [options.style] Map style. This must be an an object conforming to the schema described in the [style reference](https://mapbox.com/mapbox-gl-style-spec/), or a URL to a JSON style. To load a style from the Mapbox API, you can use a URL of the form `mapbox://styles/:owner/:style`, where `:owner` is your Mapbox account name and `:style` is the style ID. Or you can use one of the predefined Mapbox styles: - * * `mapbox://styles/mapbox/basic-v8` - Simple and flexible starting template. - * * `mapbox://styles/mapbox/bright-v8` - Template for complex custom basemaps. - * * `mapbox://styles/mapbox/streets-v8` - A ready-to-use basemap, perfect for minor customization or incorporating your own data. - * * `mapbox://styles/mapbox/light-v8` - Subtle light backdrop for data vizualizations. - * * `mapbox://styles/mapbox/dark-v8` - Subtle dark backdrop for data vizualizations. - * @param {boolean} [options.hash=false] If `true`, the map will track and update the page URL according to map position - * @param {boolean} [options.interactive=true] If `false`, no mouse, touch, or keyboard listeners are attached to the map, so it will not respond to input - * @param {number} [options.bearingSnap=7] Snap to north threshold in degrees. - * @param {Array} [options.classes] Style class names with which to initialize the map - * @param {boolean} [options.attributionControl=true] If `true`, an attribution control will be added to the map. - * @param {boolean} [options.failIfMajorPerformanceCaveat=false] If `true`, map creation will fail if the implementation determines that the performance of the created WebGL context would be dramatically lower than expected. - * @param {boolean} [options.preserveDrawingBuffer=false] If `true`, The maps canvas can be exported to a PNG using `map.getCanvas().toDataURL();`. This is false by default as a performance optimization. - * @param {LngLatBounds|Array>} [options.maxBounds] If set, the map is constrained to the given bounds. - * @param {boolean} [options.scrollZoom=true] If `true`, enable the "scroll to zoom" interaction (see `ScrollZoomHandler`) - * @param {boolean} [options.boxZoom=true] If `true`, enable the "box zoom" interaction (see `BoxZoomHandler`) - * @param {boolean} [options.dragRotate=true] If `true`, enable the "drag to rotate" interaction (see `DragRotateHandler`). - * @param {boolean} [options.dragPan=true] If `true`, enable the "drag to pan" interaction (see `DragPanHandler`). - * @param {boolean} [options.keyboard=true] If `true`, enable keyboard shortcuts (see `KeyboardHandler`). - * @param {boolean} [options.doubleClickZoom=true] If `true`, enable the "double click to zoom" interaction (see `DoubleClickZoomHandler`). - * @param {boolean} [options.touchZoomRotate=true] If `true`, enable the "pinch to rotate and zoom" interaction (see `TouchZoomRotateHandler`). - * @example - * var map = new mapboxgl.Map({ - * container: 'map', - * center: [-122.420679, 37.772537], - * zoom: 13, - * style: style_object, - * hash: true - * }); - */ -var Map = module.exports = function(options) { - - options = this.options = util.inherit(this.options, options); - - this.animationLoop = new AnimationLoop(); - this.transform = new Transform(options.minZoom, options.maxZoom); - - if (options.maxBounds) { - var b = LngLatBounds.convert(options.maxBounds); - this.transform.lngRange = [b.getWest(), b.getEast()]; - this.transform.latRange = [b.getSouth(), b.getNorth()]; - } - - util.bindAll([ - '_forwardStyleEvent', - '_forwardSourceEvent', - '_forwardLayerEvent', - '_forwardTileEvent', - '_onStyleLoad', - '_onStyleChange', - '_onSourceAdd', - '_onSourceRemove', - '_onSourceUpdate', - '_onWindowResize', - 'onError', - '_update', - '_render' - ], this); - - this._setupContainer(); - this._setupPainter(); - - this.on('move', this._update.bind(this, false)); - this.on('zoom', this._update.bind(this, true)); - this.on('moveend', function() { - this.animationLoop.set(300); // text fading - this._rerender(); - }.bind(this)); - - if (typeof window !== 'undefined') { - window.addEventListener('resize', this._onWindowResize, false); +WorkerTile.prototype.redoPlacement = function (angle, pitch, showCollisionBoxes) { + if (this.status !== 'done') { + this.redoPlacementAfterDone = true; + this.angle = angle; + return {}; } - - this.interaction = new Interaction(this); - - if (options.interactive) { - this.interaction.enable(); + var collisionTile = new CollisionTile(angle, pitch, this.collisionBoxArray); + var buckets = this.symbolBuckets; + for (var i = buckets.length - 1; i >= 0; i--) { + buckets[i].placeFeatures(collisionTile, showCollisionBoxes); } - - this._hash = options.hash && (new Hash()).addTo(this); - // don't set position from options if set through hash - if (!this._hash || !this._hash._onHashChange()) { - this.jumpTo(options); + var collisionTile_ = collisionTile.serialize(); + var nonEmptyBuckets = buckets.filter(isBucketNonEmpty); + return { + result: { + buckets: nonEmptyBuckets.map(serializeBucket), + collisionTile: collisionTile_.data + }, + transferables: getTransferables(nonEmptyBuckets).concat(collisionTile_.transferables) + }; +}; +function isBucketNonEmpty(bucket) { + return !bucket.isEmpty(); +} +function serializeBucket(bucket) { + return bucket.serialize(); +} +function getTransferables(buckets) { + var transferables = []; + for (var i in buckets) { + buckets[i].getTransferables(transferables); } - - this.sources = {}; - this.stacks = {}; - this._classes = {}; - - this.resize(); - - if (options.classes) this.setClasses(options.classes); - if (options.style) this.setStyle(options.style); - if (options.attributionControl) this.addControl(new Attribution(options.attributionControl)); - - this.on('style.error', this.onError); - this.on('source.error', this.onError); - this.on('tile.error', this.onError); + return transferables; +} +function getLayerId(layer) { + return layer.id; +} +},{"../data/bucket":72,"../data/feature_index":79,"../symbol/collision_box":138,"../symbol/collision_tile":140,"../symbol/symbol_instances":149,"../symbol/symbol_quads":150,"../util/dictionary_coder":176,"../util/util":188}],119:[function(require,module,exports){ +'use strict'; +module.exports = AnimationLoop; +function AnimationLoop() { + this.n = 0; + this.times = []; +} +AnimationLoop.prototype.stopped = function () { + this.times = this.times.filter(function (t) { + return t.time >= new Date().getTime(); + }); + return !this.times.length; }; - -util.extend(Map.prototype, Evented); -util.extend(Map.prototype, Camera.prototype); -util.extend(Map.prototype, /** @lends Map.prototype */{ - - options: { - center: [0, 0], - zoom: 0, - bearing: 0, - pitch: 0, - - minZoom: 0, - maxZoom: 20, - - interactive: true, - - scrollZoom: true, - boxZoom: true, - dragRotate: true, - dragPan: true, - keyboard: true, - doubleClickZoom: true, - touchZoomRotate: true, - - bearingSnap: 7, - - hash: false, - - attributionControl: true, - - failIfMajorPerformanceCaveat: false, - preserveDrawingBuffer: false - }, - - /** - * Adds a control to the map, calling `control.addTo(this)`. - * - * @param {Control} control - * @returns {Map} `this` - */ - addControl: function(control) { - control.addTo(this); - return this; - }, - - /** - * Adds a style class to a map - * - * @param {string} klass name of style class - * @param {StyleOptions} [options] - * @fires change - * @returns {Map} `this` - */ - addClass: function(klass, options) { - if (this._classes[klass]) return; - this._classes[klass] = true; - if (this.style) this.style._cascade(this._classes, options); - }, - - /** - * Removes a style class from a map - * - * @param {string} klass name of style class - * @param {StyleOptions} [options] - * @fires change - * @returns {Map} `this` - */ - removeClass: function(klass, options) { - if (!this._classes[klass]) return; - delete this._classes[klass]; - if (this.style) this.style._cascade(this._classes, options); - }, - - /** - * Helper method to add more than one class - * - * @param {Array} klasses An array of class names - * @param {StyleOptions} [options] - * @fires change - * @returns {Map} `this` - */ - setClasses: function(klasses, options) { - this._classes = {}; - for (var i = 0; i < klasses.length; i++) { - this._classes[klasses[i]] = true; +AnimationLoop.prototype.set = function (t) { + this.times.push({ + id: this.n, + time: t + new Date().getTime() + }); + return this.n++; +}; +AnimationLoop.prototype.cancel = function (n) { + this.times = this.times.filter(function (t) { + return t.id !== n; + }); +}; +},{}],120:[function(require,module,exports){ +'use strict'; +var Evented = require('../util/evented'); +var ajax = require('../util/ajax'); +var browser = require('../util/browser'); +var normalizeURL = require('../util/mapbox').normalizeSpriteURL; +module.exports = ImageSprite; +function ImageSprite(base) { + this.base = base; + this.retina = browser.devicePixelRatio > 1; + var format = this.retina ? '@2x' : ''; + ajax.getJSON(normalizeURL(base, format, '.json'), function (err, data) { + if (err) { + this.fire('error', { error: err }); + return; } - if (this.style) this.style._cascade(this._classes, options); - }, - - /** - * Check whether a style class is active - * - * @param {string} klass Name of style class - * @returns {boolean} - */ - hasClass: function(klass) { - return !!this._classes[klass]; - }, - - /** - * Return an array of the current active style classes - * - * @returns {boolean} - */ - getClasses: function() { - return Object.keys(this._classes); - }, - - /** - * Detect the map's new width and height and resize it. - * - * @returns {Map} `this` - */ - resize: function() { - var width = 0, height = 0; - - if (this._container) { - width = this._container.offsetWidth || 400; - height = this._container.offsetHeight || 300; + this.data = data; + if (this.img) + this.fire('data', { dataType: 'style' }); + }.bind(this)); + ajax.getImage(normalizeURL(base, format, '.png'), function (err, img) { + if (err) { + this.fire('error', { error: err }); + return; } - - this._canvas.resize(width, height); - this.transform.resize(width, height); - this.painter.resize(width, height); - - return this - .fire('movestart') - .fire('move') - .fire('resize') - .fire('moveend'); - }, - - /** - * Get the map's geographical bounds - * - * @returns {LngLatBounds} - */ - getBounds: function() { - return new LngLatBounds( - this.transform.pointLocation(new Point(0, 0)), - this.transform.pointLocation(this.transform.size)); - }, - - /** - * Get pixel coordinates (relative to map container) given a geographical location - * - * @param {LngLat} lnglat - * @returns {Object} `x` and `y` coordinates - */ - project: function(lnglat) { - return this.transform.locationPoint(LngLat.convert(lnglat)); - }, - - /** - * Get geographical coordinates given pixel coordinates - * - * @param {Array} point [x, y] pixel coordinates - * @returns {LngLat} - */ - unproject: function(point) { - return this.transform.pointLocation(Point.convert(point)); - }, - - /** - * Query features at a point, or within a certain radius thereof. - * - * To use this method, you must set the style property `"interactive": true` on layers you wish to query. - * - * @param {Array} point [x, y] pixel coordinates - * @param {Object} params - * @param {number} [params.radius=0] Radius in pixels to search in - * @param {string|Array} [params.layer] Only return features from a given layer or layers - * @param {string} [params.type] Either `raster` or `vector` - * @param {boolean} [params.includeGeometry=false] If `true`, geometry of features will be included in the results at the expense of a much slower query time. - * @param {featuresCallback} callback function that receives the results - * - * @returns {Map} `this` - * - * @example - * map.featuresAt([10, 20], { radius: 10 }, function(err, features) { - * console.log(features); - * }); - */ - featuresAt: function(point, params, callback) { - var location = this.unproject(point).wrap(); - var coord = this.transform.locationCoordinate(location); - this.style.featuresAt(coord, params, callback); - return this; - }, - - /** - * Query features within a rectangle. - * - * To use this method, you must set the style property `"interactive": true` on layers you wish to query. - * - * @param {Array|Array>} [bounds] Coordinates of opposite corners of bounding rectangle, in pixel coordinates. Optional: use entire viewport if omitted. - * @param {Object} params - * @param {string|Array} [params.layer] Only return features from a given layer or layers - * @param {string} [params.type] Either `raster` or `vector` - * @param {boolean} [params.includeGeometry=false] If `true`, geometry of features will be included in the results at the expense of a much slower query time. - * @param {featuresCallback} callback function that receives the results - * - * @returns {Map} `this` - * - * @example - * map.featuresIn([[10, 20], [30, 50]], { layer: 'my-layer-name' }, function(err, features) { - * console.log(features); - * }); - */ - featuresIn: function(bounds, params, callback) { - if (typeof callback === 'undefined') { - callback = params; - params = bounds; - // bounds was omitted: use full viewport - bounds = [ - Point.convert([0, 0]), - Point.convert([this.transform.width, this.transform.height]) - ]; + var data = img.getData(); + var newdata = img.data = new Uint8Array(data.length); + for (var i = 0; i < data.length; i += 4) { + var alpha = data[i + 3] / 255; + newdata[i + 0] = data[i + 0] * alpha; + newdata[i + 1] = data[i + 1] * alpha; + newdata[i + 2] = data[i + 2] * alpha; + newdata[i + 3] = data[i + 3]; } - bounds = bounds.map(Point.convert.bind(Point)); - bounds = [ - new Point( - Math.min(bounds[0].x, bounds[1].x), - Math.min(bounds[0].y, bounds[1].y) - ), - new Point( - Math.max(bounds[0].x, bounds[1].x), - Math.max(bounds[0].y, bounds[1].y) - ) - ].map(this.transform.pointCoordinate.bind(this.transform)); - this.style.featuresIn(bounds, params, callback); - return this; - }, - - /** - * Apply multiple style mutations in a batch - * - * @param {function} work Function which accepts a `StyleBatch` object, - * a subset of `Map`, with `addLayer`, `removeLayer`, - * `setPaintProperty`, `setLayoutProperty`, `setFilter`, - * `setLayerZoomRange`, `addSource`, and `removeSource` - * - * @example - * map.batch(function (batch) { - * batch.addLayer(layer1); - * batch.addLayer(layer2); - * ... - * batch.addLayer(layerN); - * }); - * - */ - batch: function(work) { - this.style.batch(work); - - this.style._cascade(this._classes); - this._update(true); - }, - - /** - * Replaces the map's style object - * - * @param {Object} style A style object formatted as JSON - * @returns {Map} `this` - */ - setStyle: function(style) { - if (this.style) { - this.style - .off('load', this._onStyleLoad) - .off('error', this._forwardStyleEvent) - .off('change', this._onStyleChange) - .off('source.add', this._onSourceAdd) - .off('source.remove', this._onSourceRemove) - .off('source.load', this._onSourceUpdate) - .off('source.error', this._forwardSourceEvent) - .off('source.change', this._onSourceUpdate) - .off('layer.add', this._forwardLayerEvent) - .off('layer.remove', this._forwardLayerEvent) - .off('tile.add', this._forwardTileEvent) - .off('tile.remove', this._forwardTileEvent) - .off('tile.load', this._update) - .off('tile.error', this._forwardTileEvent) - .off('tile.stats', this._forwardTileEvent) - ._remove(); - - this.off('rotate', this.style._redoPlacement); - this.off('pitch', this.style._redoPlacement); + this.img = img; + if (this.data) + this.fire('data', { dataType: 'style' }); + }.bind(this)); +} +ImageSprite.prototype = Object.create(Evented); +ImageSprite.prototype.toJSON = function () { + return this.base; +}; +ImageSprite.prototype.loaded = function () { + return !!(this.data && this.img); +}; +ImageSprite.prototype.resize = function () { + if (browser.devicePixelRatio > 1 !== this.retina) { + var newSprite = new ImageSprite(this.base); + newSprite.on('data', function () { + this.img = newSprite.img; + this.data = newSprite.data; + this.retina = newSprite.retina; + }.bind(this)); + } +}; +function SpritePosition() { +} +SpritePosition.prototype = { + x: 0, + y: 0, + width: 0, + height: 0, + pixelRatio: 1, + sdf: false +}; +ImageSprite.prototype.getSpritePosition = function (name) { + if (!this.loaded()) + return new SpritePosition(); + var pos = this.data && this.data[name]; + if (pos && this.img) + return pos; + return new SpritePosition(); +}; +},{"../util/ajax":170,"../util/browser":171,"../util/evented":179,"../util/mapbox":185}],121:[function(require,module,exports){ +'use strict'; +var parseColorString = require('csscolorparser').parseCSSColor; +var util = require('../util/util'); +var StyleFunction = require('./style_function'); +var cache = {}; +module.exports = function parseColor(input) { + if (StyleFunction.isFunctionDefinition(input)) { + return util.extend({}, input, { + stops: input.stops.map(function (stop) { + return [ + stop[0], + parseColor(stop[1]) + ]; + }) + }); + } else if (typeof input === 'string') { + if (!cache[input]) { + var rgba = parseColorString(input); + if (!rgba) { + throw new Error('Invalid color ' + input); + } + cache[input] = [ + rgba[0] / 255 * rgba[3], + rgba[1] / 255 * rgba[3], + rgba[2] / 255 * rgba[3], + rgba[3] + ]; + } + return cache[input]; + } else { + throw new Error('Invalid color ' + input); + } +}; +},{"../util/util":188,"./style_function":124,"csscolorparser":10}],122:[function(require,module,exports){ +'use strict'; +var Evented = require('../util/evented'); +var StyleLayer = require('./style_layer'); +var ImageSprite = require('./image_sprite'); +var GlyphSource = require('../symbol/glyph_source'); +var SpriteAtlas = require('../symbol/sprite_atlas'); +var LineAtlas = require('../render/line_atlas'); +var util = require('../util/util'); +var ajax = require('../util/ajax'); +var mapbox = require('../util/mapbox'); +var browser = require('../util/browser'); +var Dispatcher = require('../util/dispatcher'); +var AnimationLoop = require('./animation_loop'); +var validateStyle = require('./validate_style'); +var Source = require('../source/source'); +var QueryFeatures = require('../source/query_features'); +var SourceCache = require('../source/source_cache'); +var styleSpec = require('./style_spec'); +var StyleFunction = require('./style_function'); +var getWorkerPool = require('../global_worker_pool'); +module.exports = Style; +function Style(stylesheet, map, options) { + this.map = map; + this.animationLoop = map && map.animationLoop || new AnimationLoop(); + this.dispatcher = new Dispatcher(getWorkerPool(), this); + this.spriteAtlas = new SpriteAtlas(1024, 1024); + this.lineAtlas = new LineAtlas(256, 512); + this._layers = {}; + this._order = []; + this._groups = []; + this.sourceCaches = {}; + this.zoomHistory = {}; + util.bindAll(['_redoPlacement'], this); + this._resetUpdates(); + options = util.extend({ validate: typeof stylesheet === 'string' ? !mapbox.isMapboxURL(stylesheet) : true }, options); + var stylesheetLoaded = function (err, stylesheet) { + if (err) { + this.fire('error', { error: err }); + return; + } + if (options.validate && validateStyle.emitErrors(this, validateStyle(stylesheet))) + return; + this._loaded = true; + this.stylesheet = stylesheet; + this.updateClasses(); + for (var id in stylesheet.sources) { + this.addSource(id, stylesheet.sources[id], options); + } + if (stylesheet.sprite) { + this.sprite = new ImageSprite(stylesheet.sprite); + this.sprite.setEventedParent(this); + } + this.glyphSource = new GlyphSource(stylesheet.glyphs); + this._resolve(); + this.fire('data', { dataType: 'style' }); + this.fire('style.load'); + }.bind(this); + if (typeof stylesheet === 'string') { + ajax.getJSON(mapbox.normalizeStyleURL(stylesheet), stylesheetLoaded); + } else { + browser.frame(stylesheetLoaded.bind(this, null, stylesheet)); + } + this.on('source.load', function (event) { + var source = event.source; + if (source && source.vectorLayerIds) { + for (var layerId in this._layers) { + var layer = this._layers[layerId]; + if (layer.source === source.id) { + this._validateLayer(layer); + } + } + } + }); +} +Style.prototype = util.inherit(Evented, { + _loaded: false, + _validateLayer: function (layer) { + var sourceCache = this.sourceCaches[layer.source]; + if (!layer.sourceLayer) + return; + if (!sourceCache) + return; + var source = sourceCache.getSource(); + if (!source.vectorLayerIds) + return; + if (source.vectorLayerIds.indexOf(layer.sourceLayer) === -1) { + this.fire('error', { error: new Error('Source layer "' + layer.sourceLayer + '" ' + 'does not exist on source "' + source.id + '" ' + 'as specified by style layer "' + layer.id + '"') }); } - - if (!style) { - this.style = null; - return this; - } else if (style instanceof Style) { - this.style = style; - } else { - this.style = new Style(style, this.animationLoop); - } - - this.style - .on('load', this._onStyleLoad) - .on('error', this._forwardStyleEvent) - .on('change', this._onStyleChange) - .on('source.add', this._onSourceAdd) - .on('source.remove', this._onSourceRemove) - .on('source.load', this._onSourceUpdate) - .on('source.error', this._forwardSourceEvent) - .on('source.change', this._onSourceUpdate) - .on('layer.add', this._forwardLayerEvent) - .on('layer.remove', this._forwardLayerEvent) - .on('tile.add', this._forwardTileEvent) - .on('tile.remove', this._forwardTileEvent) - .on('tile.load', this._update) - .on('tile.error', this._forwardTileEvent) - .on('tile.stats', this._forwardTileEvent); - - this.on('rotate', this.style._redoPlacement); - this.on('pitch', this.style._redoPlacement); - - return this; }, - - /** - * Get a style object that can be used to recreate the map's style - * - * @returns {Object} style - */ - getStyle: function() { - return this.style.serialize(); - }, - - /** - * Add a source to the map style. - * - * @param {string} id ID of the source. Must not be used by any existing source. - * @param {Object} source source specification, following the - * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources) - * @fires source.add - * @returns {Map} `this` - */ - addSource: function(id, source) { - this.style.addSource(id, source); - return this; + loaded: function () { + if (!this._loaded) + return false; + if (Object.keys(this._updates.sources).length) + return false; + for (var id in this.sourceCaches) + if (!this.sourceCaches[id].loaded()) + return false; + if (this.sprite && !this.sprite.loaded()) + return false; + return true; }, - - /** - * Remove an existing source from the map style. - * - * @param {string} id ID of the source to remove - * @fires source.remove - * @returns {Map} `this` - */ - removeSource: function(id) { - this.style.removeSource(id); - return this; + _resolve: function () { + var layer, layerJSON; + this._layers = {}; + this._order = this.stylesheet.layers.map(function (layer) { + return layer.id; + }); + for (var i = 0; i < this.stylesheet.layers.length; i++) { + layerJSON = this.stylesheet.layers[i]; + if (layerJSON.ref) + continue; + layer = StyleLayer.create(layerJSON); + this._layers[layer.id] = layer; + layer.setEventedParent(this, { layer: { id: layer.id } }); + } + for (var j = 0; j < this.stylesheet.layers.length; j++) { + layerJSON = this.stylesheet.layers[j]; + if (!layerJSON.ref) + continue; + var refLayer = this.getLayer(layerJSON.ref); + layer = StyleLayer.create(layerJSON, refLayer); + this._layers[layer.id] = layer; + layer.setEventedParent(this, { layer: { id: layer.id } }); + } + this._groupLayers(); + this._updateWorkerLayers(); }, - - /** - * Return the style source object with the given `id`. - * - * @param {string} id source ID - * @returns {Object} - */ - getSource: function(id) { - return this.style.getSource(id); + _groupLayers: function () { + var group; + this._groups = []; + for (var i = 0; i < this._order.length; ++i) { + var layer = this._layers[this._order[i]]; + if (!group || layer.source !== group.source) { + group = []; + group.source = layer.source; + this._groups.push(group); + } + group.push(layer); + } }, - - /** - * Add a layer to the map style. The layer will be inserted before the layer with - * ID `before`, or appended if `before` is omitted. - * @param {StyleLayer|Object} layer - * @param {string=} before ID of an existing layer to insert before - * @fires layer.add - * @returns {Map} `this` - */ - addLayer: function(layer, before) { - this.style.addLayer(layer, before); - this.style._cascade(this._classes); - return this; + _updateWorkerLayers: function (ids) { + this.dispatcher.broadcast(ids ? 'update layers' : 'set layers', this._serializeLayers(ids)); }, - - /** - * Remove the layer with the given `id` from the map. Any layers which refer to the - * specified layer via a `ref` property are also removed. - * - * @param {string} id layer id - * @throws {Error} if no layer with the given `id` exists - * @fires layer.remove - * @returns {Map} `this` - */ - removeLayer: function(id) { - this.style.removeLayer(id); - this.style._cascade(this._classes); - return this; + _serializeLayers: function (ids) { + ids = ids || this._order; + var serialized = []; + var options = { includeRefProperties: true }; + for (var i = 0; i < ids.length; i++) { + serialized.push(this._layers[ids[i]].serialize(options)); + } + return serialized; }, - - /** - * Return the style layer object with the given `id`. - * - * @param {string} id layer id - * @returns {?Object} a layer, if one with the given `id` exists - */ - getLayer: function(id) { - return this.style.getLayer(id); + _applyClasses: function (classes, options) { + if (!this._loaded) + return; + classes = classes || []; + options = options || { transition: true }; + var transition = this.stylesheet.transition || {}; + var layers = this._updates.allPaintProps ? this._layers : this._updates.paintProps; + for (var id in layers) { + var layer = this._layers[id]; + var props = this._updates.paintProps[id]; + if (this._updates.allPaintProps || props.all) { + layer.updatePaintTransitions(classes, options, transition, this.animationLoop); + } else { + for (var paintName in props) { + this._layers[id].updatePaintTransition(paintName, classes, options, transition, this.animationLoop); + } + } + } }, - - /** - * Set the filter for a given style layer. - * - * @param {string} layer ID of a layer - * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#types-filter) - * @returns {Map} `this` - */ - setFilter: function(layer, filter) { - this.style.setFilter(layer, filter); - return this; + _recalculate: function (z) { + for (var sourceId in this.sourceCaches) + this.sourceCaches[sourceId].used = false; + this._updateZoomHistory(z); + this.rasterFadeDuration = 300; + for (var layerId in this._layers) { + var layer = this._layers[layerId]; + layer.recalculate(z, this.zoomHistory); + if (!layer.isHidden(z) && layer.source) { + this.sourceCaches[layer.source].used = true; + } + } + var maxZoomTransitionDuration = 300; + if (Math.floor(this.z) !== Math.floor(z)) { + this.animationLoop.set(maxZoomTransitionDuration); + } + this.z = z; }, - - /** - * Set the zoom extent for a given style layer. - * - * @param {string} layerId ID of a layer - * @param {number} minzoom minimum zoom extent - * @param {number} maxzoom maximum zoom extent - * @returns {Map} `this` - */ - setLayerZoomRange: function(layerId, minzoom, maxzoom) { - this.style.setLayerZoomRange(layerId, minzoom, maxzoom); - return this; + _updateZoomHistory: function (z) { + var zh = this.zoomHistory; + if (zh.lastIntegerZoom === undefined) { + zh.lastIntegerZoom = Math.floor(z); + zh.lastIntegerZoomTime = 0; + zh.lastZoom = z; + } + if (Math.floor(zh.lastZoom) < Math.floor(z)) { + zh.lastIntegerZoom = Math.floor(z); + zh.lastIntegerZoomTime = Date.now(); + } else if (Math.floor(zh.lastZoom) > Math.floor(z)) { + zh.lastIntegerZoom = Math.floor(z + 1); + zh.lastIntegerZoomTime = Date.now(); + } + zh.lastZoom = z; }, - - /** - * Get the filter for a given style layer. - * - * @param {string} layer ID of a layer - * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter) - */ - getFilter: function(layer) { - return this.style.getFilter(layer); + _checkLoaded: function () { + if (!this._loaded) { + throw new Error('Style is not done loading'); + } }, - - /** - * Set the value of a paint property in a given style layer. - * - * @param {string} layer ID of a layer - * @param {string} name name of a paint property - * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/) - * @param {string=} klass optional class specifier for the property - * @returns {Map} `this` - */ - setPaintProperty: function(layer, name, value, klass) { - this.batch(function(batch) { - batch.setPaintProperty(layer, name, value, klass); - }); - + update: function (classes, options) { + if (!this._updates.changed) + return this; + if (this._updates.allLayers) { + this._groupLayers(); + this._updateWorkerLayers(); + } else { + var updatedIds = Object.keys(this._updates.layers); + if (updatedIds.length) { + this._updateWorkerLayers(updatedIds); + } + } + var updatedSourceIds = Object.keys(this._updates.sources); + var i; + for (i = 0; i < updatedSourceIds.length; i++) { + this._reloadSource(updatedSourceIds[i]); + } + for (i = 0; i < this._updates.events.length; i++) { + var args = this._updates.events[i]; + this.fire(args[0], args[1]); + } + this._applyClasses(classes, options); + if (this._updates.changed) { + this.fire('data', { dataType: 'style' }); + } + this._resetUpdates(); return this; }, - - /** - * Get the value of a paint property in a given style layer. - * - * @param {string} layer ID of a layer - * @param {string} name name of a paint property - * @param {string=} klass optional class specifier for the property - * @returns {*} value for the paint propery - */ - getPaintProperty: function(layer, name, klass) { - return this.style.getPaintProperty(layer, name, klass); + _resetUpdates: function () { + this._updates = { + events: [], + layers: {}, + sources: {}, + paintProps: {} + }; }, - - /** - * Set the value of a layout property in a given style layer. - * - * @param {string} layer ID of a layer - * @param {string} name name of a layout property - * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/) - * @returns {Map} `this` - */ - setLayoutProperty: function(layer, name, value) { - this.batch(function(batch) { - batch.setLayoutProperty(layer, name, value); - }); - + addSource: function (id, source, options) { + this._checkLoaded(); + if (this.sourceCaches[id] !== undefined) { + throw new Error('There is already a source with this ID'); + } + if (!source.type) { + throw new Error('The type property must be defined, but the only the following properties were given: ' + Object.keys(source) + '.'); + } + var builtIns = [ + 'vector', + 'raster', + 'geojson', + 'video', + 'image' + ]; + var shouldValidate = builtIns.indexOf(source.type) >= 0; + if (shouldValidate && this._validate(validateStyle.source, 'sources.' + id, source, null, options)) + return this; + source = new SourceCache(id, source, this.dispatcher); + this.sourceCaches[id] = source; + source.style = this; + source.setEventedParent(this, { source: source.getSource() }); + if (source.onAdd) + source.onAdd(this.map); + this._updates.changed = true; return this; }, - - /** - * Get the value of a layout property in a given style layer. - * - * @param {string} layer ID of a layer - * @param {string} name name of a layout property - * @param {string=} klass optional class specifier for the property - * @returns {*} value for the layout propery - */ - getLayoutProperty: function(layer, name) { - return this.style.getLayoutProperty(layer, name); - }, - - /** - * Get the Map's container as an HTML element - * @returns {HTMLElement} container - */ - getContainer: function() { - return this._container; + removeSource: function (id) { + this._checkLoaded(); + if (this.sourceCaches[id] === undefined) { + throw new Error('There is no source with this ID'); + } + var sourceCache = this.sourceCaches[id]; + delete this.sourceCaches[id]; + delete this._updates.sources[id]; + sourceCache.setEventedParent(null); + if (sourceCache.onRemove) + sourceCache.onRemove(this.map); + this._updates.changed = true; + return this; }, - - /** - * Get the container for the map `canvas` element. - * - * If you want to add non-GL overlays to the map, you should append them to this element. This - * is the element to which event bindings for map interactivity such as panning and zooming are - * attached. It will receive bubbled events for child elements such as the `canvas`, but not for - * map controls. - * - * @returns {HTMLElement} container - */ - getCanvasContainer: function() { - return this._canvasContainer; + getSource: function (id) { + return this.sourceCaches[id] && this.sourceCaches[id].getSource(); }, - - /** - * Get the Map's canvas as an HTML canvas - * @returns {HTMLElement} canvas - */ - getCanvas: function() { - return this._canvas.getElement(); + addLayer: function (layer, before, options) { + this._checkLoaded(); + if (!(layer instanceof StyleLayer)) { + if (this._validate(validateStyle.layer, 'layers.' + layer.id, layer, { arrayIndex: -1 }, options)) + return this; + var refLayer = layer.ref && this.getLayer(layer.ref); + layer = StyleLayer.create(layer, refLayer); + } + this._validateLayer(layer); + layer.setEventedParent(this, { layer: { id: layer.id } }); + this._layers[layer.id] = layer; + this._order.splice(before ? this._order.indexOf(before) : Infinity, 0, layer.id); + this._updates.allLayers = true; + if (layer.source) { + this._updates.sources[layer.source] = true; + } + return this.updateClasses(layer.id); }, - - _setupContainer: function() { - var id = this.options.container; - - var container = this._container = typeof id === 'string' ? document.getElementById(id) : id; - container.classList.add('mapboxgl-map'); - - var canvasContainer = this._canvasContainer = DOM.create('div', 'mapboxgl-canvas-container', container); - if (this.options.interactive) { - canvasContainer.classList.add('mapboxgl-interactive'); + removeLayer: function (id) { + this._checkLoaded(); + var layer = this._layers[id]; + if (layer === undefined) { + throw new Error('There is no layer with this ID'); } - this._canvas = new Canvas(this, canvasContainer); - - var controlContainer = this._controlContainer = DOM.create('div', 'mapboxgl-control-container', container); - var corners = this._controlCorners = {}; - ['top-left', 'top-right', 'bottom-left', 'bottom-right'].forEach(function (pos) { - corners[pos] = DOM.create('div', 'mapboxgl-ctrl-' + pos, controlContainer); - }); + for (var i in this._layers) { + if (this._layers[i].ref === id) { + this.removeLayer(i); + } + } + layer.setEventedParent(null); + delete this._layers[id]; + delete this._updates.layers[id]; + delete this._updates.paintProps[id]; + this._order.splice(this._order.indexOf(id), 1); + this._updates.allLayers = true; + this._updates.changed = true; + return this; }, - - _setupPainter: function() { - var gl = this._canvas.getWebGLContext({ - failIfMajorPerformanceCaveat: this.options.failIfMajorPerformanceCaveat, - preserveDrawingBuffer: this.options.preserveDrawingBuffer - }); - - if (!gl) { - console.error('Failed to initialize WebGL'); - return; + getLayer: function (id) { + return this._layers[id]; + }, + getReferentLayer: function (id) { + var layer = this.getLayer(id); + if (layer.ref) { + layer = this.getLayer(layer.ref); } - - this.painter = new Painter(gl, this.transform); + return layer; }, - - /** - * WebGL Context Lost event. - * - * @event webglcontextlost - * @memberof Map - * @instance - * @type {Object} - * @property {Event} originalEvent the original DOM event - */ - _contextLost: function(event) { - event.preventDefault(); - if (this._frameId) { - browser.cancelFrame(this._frameId); + setLayerZoomRange: function (layerId, minzoom, maxzoom) { + this._checkLoaded(); + var layer = this.getReferentLayer(layerId); + if (layer.minzoom === minzoom && layer.maxzoom === maxzoom) + return this; + if (minzoom != null) { + layer.minzoom = minzoom; + } + if (maxzoom != null) { + layer.maxzoom = maxzoom; } - this.fire("webglcontextlost", {originalEvent: event}); + return this._updateLayer(layer); }, - - /** - * WebGL Context Restored event. - * - * @event webglcontextrestored - * @memberof Map - * @instance - * @type {Object} - */ - _contextRestored: function(event) { - this._setupPainter(); - this.resize(); - this._update(); - this.fire("webglcontextrestored", {originalEvent: event}); + setFilter: function (layerId, filter) { + this._checkLoaded(); + var layer = this.getReferentLayer(layerId); + if (filter !== null && this._validate(validateStyle.filter, 'layers.' + layer.id + '.filter', filter)) + return this; + if (util.deepEqual(layer.filter, filter)) + return this; + layer.filter = util.clone(filter); + return this._updateLayer(layer); }, - - /** - * Is this map fully loaded? If the style isn't loaded - * or it has a change to the sources or style that isn't - * propagated to its style, return false. - * - * @returns {boolean} whether the map is loaded - */ - loaded: function() { - if (this._styleDirty || this._sourcesDirty) - return false; - if (this.style && !this.style.loaded()) - return false; - return true; + getFilter: function (layer) { + return util.clone(this.getReferentLayer(layer).filter); }, - - /** - * Update this map's style and sources, and re-render the map. - * - * @param {boolean} updateStyle mark the map's style for reprocessing as - * well as its sources - * @returns {Map} this - * @private - */ - _update: function(updateStyle) { - if (!this.style) return this; - - this._styleDirty = this._styleDirty || updateStyle; - this._sourcesDirty = true; - - this._rerender(); - - return this; + setLayoutProperty: function (layerId, name, value) { + this._checkLoaded(); + var layer = this.getReferentLayer(layerId); + if (util.deepEqual(layer.getLayoutProperty(name), value)) + return this; + layer.setLayoutProperty(name, value); + return this._updateLayer(layer); }, - - /** - * Call when a (re-)render of the map is required, e.g. when the - * user panned or zoomed,f or new data is available. - * @returns {Map} this - * @private - */ - _render: function() { - if (this.style && this._styleDirty) { - this._styleDirty = false; - this.style._recalculate(this.transform.zoom); + getLayoutProperty: function (layer, name) { + return this.getReferentLayer(layer).getLayoutProperty(name); + }, + setPaintProperty: function (layerId, name, value, klass) { + this._checkLoaded(); + var layer = this.getLayer(layerId); + if (util.deepEqual(layer.getPaintProperty(name, klass), value)) + return this; + var wasFeatureConstant = layer.isPaintValueFeatureConstant(name); + layer.setPaintProperty(name, value, klass); + var isFeatureConstant = !(value && StyleFunction.isFunctionDefinition(value) && value.property !== '$zoom' && value.property !== undefined); + if (!isFeatureConstant || !wasFeatureConstant) { + this._updates.layers[layerId] = true; + if (layer.source) { + this._updates.sources[layer.source] = true; + } } - - if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) { - this._sourcesDirty = false; - this._sourcesDirtyTimeout = setTimeout(function() { - this._sourcesDirtyTimeout = null; - }.bind(this), 50); - this.style._updateSources(this.transform); + return this.updateClasses(layerId, name); + }, + getPaintProperty: function (layer, name, klass) { + return this.getLayer(layer).getPaintProperty(name, klass); + }, + updateClasses: function (layerId, paintName) { + this._updates.changed = true; + if (!layerId) { + this._updates.allPaintProps = true; + } else { + var props = this._updates.paintProps; + if (!props[layerId]) + props[layerId] = {}; + props[layerId][paintName || 'all'] = true; } - - this.painter.render(this.style, { - debug: this.debug, - vertices: this.vertices, - rotating: this.rotating, - zooming: this.zooming + return this; + }, + serialize: function () { + return util.filterObject({ + version: this.stylesheet.version, + name: this.stylesheet.name, + metadata: this.stylesheet.metadata, + center: this.stylesheet.center, + zoom: this.stylesheet.zoom, + bearing: this.stylesheet.bearing, + pitch: this.stylesheet.pitch, + sprite: this.stylesheet.sprite, + glyphs: this.stylesheet.glyphs, + transition: this.stylesheet.transition, + sources: util.mapObject(this.sourceCaches, function (source) { + return source.serialize(); + }), + layers: this._order.map(function (id) { + return this._layers[id].serialize(); + }, this) + }, function (value) { + return value !== undefined; }); - - this.fire('render'); - - if (this.loaded() && !this._loaded) { - this._loaded = true; - this.fire('load'); - } - - this._frameId = null; - - if (!this.animationLoop.stopped()) { - this._styleDirty = true; - } - - if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) { - this._rerender(); + }, + _updateLayer: function (layer) { + this._updates.layers[layer.id] = true; + if (layer.source) { + this._updates.sources[layer.source] = true; } - + this._updates.changed = true; return this; }, - - /** - * Destroys the map's underlying resources, including web workers and DOM elements. Afterwards, - * you must not call any further methods on this Map instance. - * - * @returns {undefined} - */ - remove: function() { - if (this._hash) this._hash.remove(); - browser.cancelFrame(this._frameId); - clearTimeout(this._sourcesDirtyTimeout); - this.setStyle(null); - if (typeof window !== 'undefined') { - window.removeEventListener('resize', this._onWindowResize, false); + _flattenRenderedFeatures: function (sourceResults) { + var features = []; + for (var l = this._order.length - 1; l >= 0; l--) { + var layerID = this._order[l]; + for (var s = 0; s < sourceResults.length; s++) { + var layerFeatures = sourceResults[s][layerID]; + if (layerFeatures) { + for (var f = 0; f < layerFeatures.length; f++) { + features.push(layerFeatures[f]); + } + } + } } - removeNode(this._canvasContainer); - removeNode(this._controlContainer); - this._container.classList.remove('mapboxgl-map'); + return features; }, - - /** - * A default error handler for `style.error`, `source.error`, and `tile.error` events. - * It logs the error via `console.error`. - * - * @example - * // Disable the default error handler - * map.off('style.error', map.onError); - * map.off('source.error', map.onError); - * map.off('tile.error', map.onError); - */ - onError: function(e) { - console.error(e.error); + queryRenderedFeatures: function (queryGeometry, params, zoom, bearing) { + if (params && params.filter) { + this._validate(validateStyle.filter, 'queryRenderedFeatures.filter', params.filter); + } + var includedSources = {}; + if (params && params.layers) { + for (var i = 0; i < params.layers.length; i++) { + var layer = this._layers[params.layers[i]]; + if (!(layer instanceof StyleLayer)) { + return this.fire('error', { error: 'The layer \'' + params.layers[i] + '\' does not exist in the map\'s style and cannot be queried for features.' }); + } + includedSources[layer.source] = true; + } + } + var sourceResults = []; + for (var id in this.sourceCaches) { + if (params.layers && !includedSources[id]) + continue; + var sourceCache = this.sourceCaches[id]; + var results = QueryFeatures.rendered(sourceCache, this._layers, queryGeometry, params, zoom, bearing); + sourceResults.push(results); + } + return this._flattenRenderedFeatures(sourceResults); }, - - _rerender: function() { - if (this.style && !this._frameId) { - this._frameId = browser.frame(this._render); + querySourceFeatures: function (sourceID, params) { + if (params && params.filter) { + this._validate(validateStyle.filter, 'querySourceFeatures.filter', params.filter); } + var sourceCache = this.sourceCaches[sourceID]; + return sourceCache ? QueryFeatures.source(sourceCache, params) : []; }, - - _forwardStyleEvent: function(e) { - this.fire('style.' + e.type, util.extend({style: e.target}, e)); + addSourceType: function (name, SourceType, callback) { + if (Source.getType(name)) { + return callback(new Error('A source type called "' + name + '" already exists.')); + } + Source.setType(name, SourceType); + if (!SourceType.workerSourceURL) { + return callback(null, null); + } + this.dispatcher.broadcast('load worker source', { + name: name, + url: SourceType.workerSourceURL + }, callback); }, - - _forwardSourceEvent: function(e) { - this.fire(e.type, util.extend({style: e.target}, e)); + _validate: function (validate, key, value, props, options) { + if (options && options.validate === false) { + return false; + } + return validateStyle.emitErrors(this, validate.call(validateStyle, util.extend({ + key: key, + style: this.serialize(), + value: value, + styleSpec: styleSpec + }, props))); }, - - _forwardLayerEvent: function(e) { - this.fire(e.type, util.extend({style: e.target}, e)); + _remove: function () { + this.dispatcher.remove(); }, - - _forwardTileEvent: function(e) { - this.fire(e.type, util.extend({style: e.target}, e)); + _reloadSource: function (id) { + this.sourceCaches[id].reload(); }, - - _onStyleLoad: function(e) { - if (this.transform.unmodified) { - this.jumpTo(this.style.stylesheet); + _updateSources: function (transform) { + for (var id in this.sourceCaches) { + this.sourceCaches[id].update(transform); } - this.style._cascade(this._classes, {transition: false}); - this._forwardStyleEvent(e); - }, - - _onStyleChange: function(e) { - this._update(true); - this._forwardStyleEvent(e); - }, - - _onSourceAdd: function(e) { - var source = e.source; - if (source.onAdd) - source.onAdd(this); - this._forwardSourceEvent(e); }, - - _onSourceRemove: function(e) { - var source = e.source; - if (source.onRemove) - source.onRemove(this); - this._forwardSourceEvent(e); + _redoPlacement: function () { + for (var id in this.sourceCaches) { + if (this.sourceCaches[id].redoPlacement) + this.sourceCaches[id].redoPlacement(); + } }, - - _onSourceUpdate: function(e) { - this._update(); - this._forwardSourceEvent(e); + 'get icons': function (mapId, params, callback) { + var sprite = this.sprite; + var spriteAtlas = this.spriteAtlas; + if (sprite.loaded()) { + spriteAtlas.setSprite(sprite); + spriteAtlas.addIcons(params.icons, callback); + } else { + sprite.on('data', function () { + spriteAtlas.setSprite(sprite); + spriteAtlas.addIcons(params.icons, callback); + }); + } }, - - _onWindowResize: function() { - this.stop().resize()._update(); + 'get glyphs': function (mapId, params, callback) { + var stacks = params.stacks, remaining = Object.keys(stacks).length, allGlyphs = {}; + for (var fontName in stacks) { + this.glyphSource.getSimpleGlyphs(fontName, stacks[fontName], params.uid, done); + } + function done(err, glyphs, fontName) { + if (err) + console.error(err); + allGlyphs[fontName] = glyphs; + remaining--; + if (remaining === 0) + callback(null, allGlyphs); + } } }); - - -/** - * Callback to receive results from `Map#featuresAt` and `Map#featuresIn`. - * - * Note: because features come from vector tiles or GeoJSON data that is converted to vector tiles internally, the returned features will be: - * - * 1. Truncated at tile boundaries. - * 2. Duplicated across tile boundaries. - * - * For example, suppose there is a highway running through your rectangle in a `featuresIn` query. `featuresIn` will only give you the parts of the highway feature that lie within the map tiles covering your rectangle, even if the road actually extends into other tiles. Also, the portion of the highway within each map tile will come back as a separate feature. - * - * @callback featuresCallback - * @param {?Error} err - An error that occurred during query processing, if any. If this parameter is non-null, the `features` parameter will be null. - * @param {?Array} features - An array of [GeoJSON](http://geojson.org/) features matching the query parameters. The GeoJSON properties of each feature are taken from the original source. Each feature object also contains a top-level `layer` property whose value is an object representing the style layer to which the feature belongs. Layout and paint properties in this object contain values which are fully evaluated for the given zoom level and feature. - */ - - -util.extendAll(Map.prototype, /** @lends Map.prototype */{ - - /** - * Enable debugging mode - * - * @name debug - * @type {boolean} - */ - _debug: false, - get debug() { return this._debug; }, - set debug(value) { - if (this._debug === value) return; - this._debug = value; - this._update(); - }, - - /** - * Show collision boxes: useful for debugging label placement - * in styles. - * - * @name collisionDebug - * @type {boolean} - */ - _collisionDebug: false, - get collisionDebug() { return this._collisionDebug; }, - set collisionDebug(value) { - if (this._collisionDebug === value) return; - this._collisionDebug = value; - this.style._redoPlacement(); - }, - - /** - * Enable continuous repaint to analyze performance - * - * @name repaint - * @type {boolean} - */ - _repaint: false, - get repaint() { return this._repaint; }, - set repaint(value) { this._repaint = value; this._update(); }, - - // show vertices - _vertices: false, - get vertices() { return this._vertices; }, - set vertices(value) { this._vertices = value; this._update(); } -}); - -function removeNode(node) { - if (node.parentNode) { - node.parentNode.removeChild(node); +},{"../global_worker_pool":85,"../render/line_atlas":98,"../source/query_features":108,"../source/source":110,"../source/source_cache":111,"../symbol/glyph_source":143,"../symbol/sprite_atlas":148,"../util/ajax":170,"../util/browser":171,"../util/dispatcher":177,"../util/evented":179,"../util/mapbox":185,"../util/util":188,"./animation_loop":119,"./image_sprite":120,"./style_function":124,"./style_layer":125,"./style_spec":132,"./validate_style":134}],123:[function(require,module,exports){ +'use strict'; +var MapboxGLFunction = require('./style_function'); +var parseColor = require('./parse_color'); +var util = require('../util/util'); +module.exports = StyleDeclaration; +function StyleDeclaration(reference, value) { + this.value = util.clone(value); + this.isFunction = MapboxGLFunction.isFunctionDefinition(value); + this.json = JSON.stringify(this.value); + var parsedValue = reference.type === 'color' && this.value ? parseColor(this.value) : value; + this.calculate = MapboxGLFunction[reference.function || 'piecewise-constant'](parsedValue); + this.isFeatureConstant = this.calculate.isFeatureConstant; + this.isZoomConstant = this.calculate.isZoomConstant; + if (reference.function === 'piecewise-constant' && reference.transition) { + this.calculate = transitioned(this.calculate); + } + if (!this.isFeatureConstant && !this.isZoomConstant) { + this.stopZoomLevels = []; + var interpolationAmountStops = []; + var stops = this.value.stops; + for (var i = 0; i < this.value.stops.length; i++) { + var zoom = stops[i][0].zoom; + if (this.stopZoomLevels.indexOf(zoom) < 0) { + this.stopZoomLevels.push(zoom); + interpolationAmountStops.push([ + zoom, + interpolationAmountStops.length + ]); + } + } + this.calculateInterpolationT = MapboxGLFunction.interpolated({ + stops: interpolationAmountStops, + base: value.base + }); } } - -},{"../geo/lng_lat":26,"../geo/lng_lat_bounds":27,"../geo/transform":28,"../render/painter":42,"../style/animation_loop":56,"../style/style":60,"../util/browser":102,"../util/canvas":103,"../util/dom":105,"../util/evented":107,"../util/util":113,"./camera":85,"./control/attribution":86,"./hash":96,"./interaction":97,"point-geometry":162}],99:[function(require,module,exports){ +function transitioned(calculate) { + return function (globalProperties, featureProperties) { + var z = globalProperties.zoom; + var zh = globalProperties.zoomHistory; + var duration = globalProperties.duration; + var fraction = z % 1; + var t = Math.min((Date.now() - zh.lastIntegerZoomTime) / duration, 1); + var fromScale = 1; + var toScale = 1; + var mix, from, to; + if (z > zh.lastIntegerZoom) { + mix = fraction + (1 - fraction) * t; + fromScale *= 2; + from = calculate({ zoom: z - 1 }, featureProperties); + to = calculate({ zoom: z }, featureProperties); + } else { + mix = 1 - (1 - t) * fraction; + to = calculate({ zoom: z }, featureProperties); + from = calculate({ zoom: z + 1 }, featureProperties); + fromScale /= 2; + } + if (from === undefined || to === undefined) { + return undefined; + } else { + return { + from: from, + fromScale: fromScale, + to: to, + toScale: toScale, + t: mix + }; + } + }; +} +},{"../util/util":188,"./parse_color":121,"./style_function":124}],124:[function(require,module,exports){ +'use strict'; +var MapboxGLFunction = require('mapbox-gl-function'); +exports.interpolated = function (parameters) { + var inner = MapboxGLFunction.interpolated(parameters); + var outer = function (globalProperties, featureProperties) { + return inner(globalProperties && globalProperties.zoom, featureProperties || {}); + }; + outer.isFeatureConstant = inner.isFeatureConstant; + outer.isZoomConstant = inner.isZoomConstant; + return outer; +}; +exports['piecewise-constant'] = function (parameters) { + var inner = MapboxGLFunction['piecewise-constant'](parameters); + var outer = function (globalProperties, featureProperties) { + return inner(globalProperties && globalProperties.zoom, featureProperties || {}); + }; + outer.isFeatureConstant = inner.isFeatureConstant; + outer.isZoomConstant = inner.isZoomConstant; + return outer; +}; +exports.isFunctionDefinition = MapboxGLFunction.isFunctionDefinition; +},{"mapbox-gl-function":45}],125:[function(require,module,exports){ 'use strict'; - -module.exports = Popup; - var util = require('../util/util'); +var StyleTransition = require('./style_transition'); +var StyleDeclaration = require('./style_declaration'); +var styleSpec = require('./style_spec'); +var validateStyle = require('./validate_style'); +var parseColor = require('./parse_color'); var Evented = require('../util/evented'); -var DOM = require('../util/dom'); -var LngLat = require('../geo/lng_lat'); - -/** - * Creates a popup component - * @class Popup - * @param {Object} options - * @param {boolean} options.closeButton - * @param {boolean} options.closeOnClick - * @param {string} options.anchor - One of "top", "bottom", "left", "right", "top-left", - * "top-right", "bottom-left", or "bottom-right", describing where the popup's anchor - * relative to the coordinate set via `setLngLat`. - * @example - * var tooltip = new mapboxgl.Popup() - * .setLngLat(e.lngLat) - * .setHTML("

Hello World!

") - * .addTo(map); - */ -function Popup(options) { - util.setOptions(this, options); - util.bindAll([ - '_update', - '_onClickClose'], - this); -} - -Popup.prototype = util.inherit(Evented, /** @lends Popup.prototype */{ - options: { - closeButton: true, - closeOnClick: true - }, - - /** - * Attaches the popup to a map - * @param {Map} map - * @returns {Popup} `this` - */ - addTo: function(map) { - this._map = map; - this._map.on('move', this._update); - if (this.options.closeOnClick) { - this._map.on('click', this._onClickClose); +module.exports = StyleLayer; +var TRANSITION_SUFFIX = '-transition'; +function StyleLayer(layer, refLayer) { + this.set(layer, refLayer); +} +StyleLayer.prototype = util.inherit(Evented, { + set: function (layer, refLayer) { + this.id = layer.id; + this.ref = layer.ref; + this.metadata = layer.metadata; + this.type = (refLayer || layer).type; + this.source = (refLayer || layer).source; + this.sourceLayer = (refLayer || layer)['source-layer']; + this.minzoom = (refLayer || layer).minzoom; + this.maxzoom = (refLayer || layer).maxzoom; + this.filter = (refLayer || layer).filter; + this.paint = {}; + this.layout = {}; + this._paintSpecifications = styleSpec['paint_' + this.type]; + this._layoutSpecifications = styleSpec['layout_' + this.type]; + this._paintTransitions = {}; + this._paintTransitionOptions = {}; + this._paintDeclarations = {}; + this._layoutDeclarations = {}; + this._layoutFunctions = {}; + var paintName, layoutName; + var options = { validate: false }; + for (var key in layer) { + var match = key.match(/^paint(?:\.(.*))?$/); + if (match) { + var klass = match[1] || ''; + for (paintName in layer[key]) { + this.setPaintProperty(paintName, layer[key][paintName], klass, options); + } + } } - this._update(); - return this; - }, - - /** - * Removes the popup from the map - * @example - * var popup = new mapboxgl.Popup().addTo(map); - * popup.remove(); - * @returns {Popup} `this` - */ - remove: function() { - if (this._content && this._content.parentNode) { - this._content.parentNode.removeChild(this._content); + if (this.ref) { + this._layoutDeclarations = refLayer._layoutDeclarations; + } else { + for (layoutName in layer.layout) { + this.setLayoutProperty(layoutName, layer.layout[layoutName], options); + } } - - if (this._container) { - this._container.parentNode.removeChild(this._container); - delete this._container; + for (paintName in this._paintSpecifications) { + this.paint[paintName] = this.getPaintValue(paintName); } - - if (this._map) { - this._map.off('move', this._update); - this._map.off('click', this._onClickClose); - delete this._map; + for (layoutName in this._layoutSpecifications) { + this._updateLayoutValue(layoutName); } - - return this; - }, - - /** - * Get the current coordinates of popup element relative to map - * @returns {LngLat} - */ - getLngLat: function() { - return this._lngLat; }, - - /** - * Set the coordinates of a popup element to a map - * @param {LngLat} lnglat - * @returns {Popup} `this` - */ - setLngLat: function(lnglat) { - this._lngLat = LngLat.convert(lnglat); - this._update(); - return this; + setLayoutProperty: function (name, value, options) { + if (value == null) { + delete this._layoutDeclarations[name]; + } else { + var key = 'layers.' + this.id + '.layout.' + name; + if (this._validate(validateStyle.layoutProperty, key, name, value, options)) + return; + this._layoutDeclarations[name] = new StyleDeclaration(this._layoutSpecifications[name], value); + } + this._updateLayoutValue(name); }, - - /** - * Fill a popup element with text only content - * @param {string} text - * @returns {Popup} `this` - */ - setText: function(text) { - this._createContent(); - this._content.appendChild(document.createTextNode(text)); - - this._update(); - return this; + getLayoutProperty: function (name) { + return this._layoutDeclarations[name] && this._layoutDeclarations[name].value; }, - - /** - * Fill a popup element with HTML content - * @param {string} html - * @returns {Popup} `this` - */ - setHTML: function(html) { - this._createContent(); - - var temp = document.createElement('body'), child; - temp.innerHTML = html; - while (true) { - child = temp.firstChild; - if (!child) break; - this._content.appendChild(child); + getLayoutValue: function (name, globalProperties, featureProperties) { + var specification = this._layoutSpecifications[name]; + var declaration = this._layoutDeclarations[name]; + if (declaration) { + return declaration.calculate(globalProperties, featureProperties); + } else { + return specification.default; } - - this._update(); - return this; }, - - _createContent: function() { - if (this._content && this._content.parentNode) { - this._content.parentNode.removeChild(this._content); - } - - this._content = DOM.create('div', 'mapboxgl-popup-content', this._container); - - if (this.options.closeButton) { - this._closeButton = DOM.create('button', 'mapboxgl-popup-close-button', this._content); - this._closeButton.innerHTML = '×'; - this._closeButton.addEventListener('click', this._onClickClose); - } - }, - - _update: function() { - if (!this._map || !this._lngLat || !this._content) { return; } - - if (!this._container) { - this._container = DOM.create('div', 'mapboxgl-popup', this._map.getContainer()); - this._tip = DOM.create('div', 'mapboxgl-popup-tip', this._container); - this._container.appendChild(this._content); - } - - var pos = this._map.project(this._lngLat).round(), - anchor = this.options.anchor; - - if (!anchor) { - var width = this._container.offsetWidth, - height = this._container.offsetHeight; - - if (pos.y < height) { - anchor = ['top']; - } else if (pos.y > this._map.transform.height - height) { - anchor = ['bottom']; + setPaintProperty: function (name, value, klass, options) { + var validateStyleKey = 'layers.' + this.id + (klass ? '["paint.' + klass + '"].' : '.paint.') + name; + if (util.endsWith(name, TRANSITION_SUFFIX)) { + if (!this._paintTransitionOptions[klass || '']) { + this._paintTransitionOptions[klass || ''] = {}; + } + if (value === null || value === undefined) { + delete this._paintTransitionOptions[klass || ''][name]; } else { - anchor = []; + if (this._validate(validateStyle.paintProperty, validateStyleKey, name, value, options)) + return; + this._paintTransitionOptions[klass || ''][name] = value; } - - if (pos.x < width / 2) { - anchor.push('left'); - } else if (pos.x > this._map.transform.width - width / 2) { - anchor.push('right'); + } else { + if (!this._paintDeclarations[klass || '']) { + this._paintDeclarations[klass || ''] = {}; } - - if (anchor.length === 0) { - anchor = 'bottom'; + if (value === null || value === undefined) { + delete this._paintDeclarations[klass || ''][name]; } else { - anchor = anchor.join('-'); + if (this._validate(validateStyle.paintProperty, validateStyleKey, name, value, options)) + return; + this._paintDeclarations[klass || ''][name] = new StyleDeclaration(this._paintSpecifications[name], value); } } - - var anchorTranslate = { - 'top': 'translate(-50%,0)', - 'top-left': 'translate(0,0)', - 'top-right': 'translate(-100%,0)', - 'bottom': 'translate(-50%,-100%)', - 'bottom-left': 'translate(0,-100%)', - 'bottom-right': 'translate(-100%,-100%)', - 'left': 'translate(0,-50%)', - 'right': 'translate(-100%,-50%)' + }, + getPaintProperty: function (name, klass) { + klass = klass || ''; + if (util.endsWith(name, TRANSITION_SUFFIX)) { + return this._paintTransitionOptions[klass] && this._paintTransitionOptions[klass][name]; + } else { + return this._paintDeclarations[klass] && this._paintDeclarations[klass][name] && this._paintDeclarations[klass][name].value; + } + }, + getPaintValue: function (name, globalProperties, featureProperties) { + var specification = this._paintSpecifications[name]; + var transition = this._paintTransitions[name]; + if (transition) { + return transition.calculate(globalProperties, featureProperties); + } else if (specification.type === 'color' && specification.default) { + return parseColor(specification.default); + } else { + return specification.default; + } + }, + getPaintValueStopZoomLevels: function (name) { + var transition = this._paintTransitions[name]; + if (transition) { + return transition.declaration.stopZoomLevels; + } else { + return []; + } + }, + getPaintInterpolationT: function (name, zoom) { + var transition = this._paintTransitions[name]; + return transition.declaration.calculateInterpolationT({ zoom: zoom }); + }, + isPaintValueFeatureConstant: function (name) { + var transition = this._paintTransitions[name]; + if (transition) { + return transition.declaration.isFeatureConstant; + } else { + return true; + } + }, + isLayoutValueFeatureConstant: function (name) { + var declaration = this._layoutDeclarations[name]; + if (declaration) { + return declaration.isFeatureConstant; + } else { + return true; + } + }, + isPaintValueZoomConstant: function (name) { + var transition = this._paintTransitions[name]; + if (transition) { + return transition.declaration.isZoomConstant; + } else { + return true; + } + }, + isHidden: function (zoom) { + if (this.minzoom && zoom < this.minzoom) + return true; + if (this.maxzoom && zoom >= this.maxzoom) + return true; + if (this.layout['visibility'] === 'none') + return true; + return false; + }, + updatePaintTransitions: function (classes, options, globalOptions, animationLoop) { + var declarations = util.extend({}, this._paintDeclarations['']); + for (var i = 0; i < classes.length; i++) { + util.extend(declarations, this._paintDeclarations[classes[i]]); + } + var name; + for (name in declarations) { + this._applyPaintDeclaration(name, declarations[name], options, globalOptions, animationLoop); + } + for (name in this._paintTransitions) { + if (!(name in declarations)) + this._applyPaintDeclaration(name, null, options, globalOptions, animationLoop); + } + }, + updatePaintTransition: function (name, classes, options, globalOptions, animationLoop) { + var declaration = this._paintDeclarations[''][name]; + for (var i = 0; i < classes.length; i++) { + var classPaintDeclarations = this._paintDeclarations[classes[i]]; + if (classPaintDeclarations && classPaintDeclarations[name]) { + declaration = classPaintDeclarations[name]; + } + } + this._applyPaintDeclaration(name, declaration, options, globalOptions, animationLoop); + }, + recalculate: function (zoom, zoomHistory) { + for (var paintName in this._paintTransitions) { + this.paint[paintName] = this.getPaintValue(paintName, { + zoom: zoom, + zoomHistory: zoomHistory + }); + } + for (var layoutName in this._layoutFunctions) { + this.layout[layoutName] = this.getLayoutValue(layoutName, { + zoom: zoom, + zoomHistory: zoomHistory + }); + } + }, + serialize: function (options) { + var output = { + 'id': this.id, + 'ref': this.ref, + 'metadata': this.metadata, + 'minzoom': this.minzoom, + 'maxzoom': this.maxzoom }; - - var classList = this._container.classList; - for (var key in anchorTranslate) { - classList.remove('mapboxgl-popup-anchor-' + key); + for (var klass in this._paintDeclarations) { + var key = klass === '' ? 'paint' : 'paint.' + klass; + output[key] = util.mapObject(this._paintDeclarations[klass], getDeclarationValue); } - classList.add('mapboxgl-popup-anchor-' + anchor); - - DOM.setTransform(this._container, anchorTranslate[anchor] + ' translate(' + pos.x + 'px,' + pos.y + 'px)'); + if (!this.ref || options && options.includeRefProperties) { + util.extend(output, { + 'type': this.type, + 'source': this.source, + 'source-layer': this.sourceLayer, + 'filter': this.filter, + 'layout': util.mapObject(this._layoutDeclarations, getDeclarationValue) + }); + } + return util.filterObject(output, function (value, key) { + return value !== undefined && !(key === 'layout' && !Object.keys(value).length); + }); }, - - _onClickClose: function() { - this.remove(); + _applyPaintDeclaration: function (name, declaration, options, globalOptions, animationLoop) { + var oldTransition = options.transition ? this._paintTransitions[name] : undefined; + var spec = this._paintSpecifications[name]; + if (declaration === null || declaration === undefined) { + declaration = new StyleDeclaration(spec, spec.default); + } + if (oldTransition && oldTransition.declaration.json === declaration.json) + return; + var transitionOptions = util.extend({ + duration: 300, + delay: 0 + }, globalOptions, this.getPaintProperty(name + TRANSITION_SUFFIX)); + var newTransition = this._paintTransitions[name] = new StyleTransition(spec, declaration, oldTransition, transitionOptions); + if (!newTransition.instant()) { + newTransition.loopID = animationLoop.set(newTransition.endTime - Date.now()); + } + if (oldTransition) { + animationLoop.cancel(oldTransition.loopID); + } + }, + _updateLayoutValue: function (name) { + var declaration = this._layoutDeclarations[name]; + if (declaration && declaration.isFunction) { + this._layoutFunctions[name] = true; + } else { + delete this._layoutFunctions[name]; + this.layout[name] = this.getLayoutValue(name); + } + }, + _validate: function (validate, key, name, value, options) { + if (options && options.validate === false) { + return false; + } + return validateStyle.emitErrors(this, validate.call(validateStyle, { + key: key, + layerType: this.type, + objectKey: name, + value: value, + styleSpec: styleSpec, + style: { + glyphs: true, + sprite: true + } + })); } }); - -},{"../geo/lng_lat":26,"../util/dom":105,"../util/evented":107,"../util/util":113}],100:[function(require,module,exports){ -'use strict'; - -module.exports = Actor; - -/** - * An implementation of the [Actor design pattern](http://en.wikipedia.org/wiki/Actor_model) - * that maintains the relationship between asynchronous tasks and the objects - * that spin them off - in this case, tasks like parsing parts of styles, - * owned by the styles - * - * @param {WebWorker} target - * @param {WebWorker} parent - * @private - */ -function Actor(target, parent) { - this.target = target; - this.parent = parent; - this.callbacks = {}; - this.callbackID = 0; - this.receive = this.receive.bind(this); - this.target.addEventListener('message', this.receive, false); +function getDeclarationValue(declaration) { + return declaration.value; } - -Actor.prototype.receive = function(message) { - var data = message.data, - callback; - - if (data.type === '') { - callback = this.callbacks[data.id]; - delete this.callbacks[data.id]; - callback(data.error || null, data.data); - } else if (typeof data.id !== 'undefined') { - var id = data.id; - this.parent[data.type](data.data, function(err, data, buffers) { - this.postMessage({ - type: '', - id: String(id), - error: err ? String(err) : null, - data: data - }, buffers); - }.bind(this)); - } else { - this.parent[data.type](data.data); - } -}; - -Actor.prototype.send = function(type, data, callback, buffers) { - var id = null; - if (callback) this.callbacks[id = this.callbackID++] = callback; - this.postMessage({ type: type, id: String(id), data: data }, buffers); +var Classes = { + background: require('./style_layer/background_style_layer'), + circle: require('./style_layer/circle_style_layer'), + fill: require('./style_layer/fill_style_layer'), + line: require('./style_layer/line_style_layer'), + raster: require('./style_layer/raster_style_layer'), + symbol: require('./style_layer/symbol_style_layer') }; - -/** - * Wrapped postMessage API that abstracts around IE's lack of - * `transferList` support. - * - * @param {Object} message - * @param {Object} transferList - * @private - */ -Actor.prototype.postMessage = function(message, transferList) { - try { - this.target.postMessage(message, transferList); - } catch (e) { - this.target.postMessage(message); // No support for transferList on IE - } +StyleLayer.create = function (layer, refLayer) { + return new Classes[(refLayer || layer).type](layer, refLayer); }; - -},{}],101:[function(require,module,exports){ +},{"../util/evented":179,"../util/util":188,"./parse_color":121,"./style_declaration":123,"./style_layer/background_style_layer":126,"./style_layer/circle_style_layer":127,"./style_layer/fill_style_layer":128,"./style_layer/line_style_layer":129,"./style_layer/raster_style_layer":130,"./style_layer/symbol_style_layer":131,"./style_spec":132,"./style_transition":133,"./validate_style":134}],126:[function(require,module,exports){ 'use strict'; - -exports.getJSON = function(url, callback) { - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, true); - xhr.setRequestHeader('Accept', 'application/json'); - xhr.onerror = function(e) { - callback(e); - }; - xhr.onload = function() { - if (xhr.status >= 200 && xhr.status < 300 && xhr.response) { - var data; - try { - data = JSON.parse(xhr.response); - } catch (err) { - return callback(err); - } - callback(null, data); +var util = require('../../util/util'); +var StyleLayer = require('../style_layer'); +function BackgroundStyleLayer() { + StyleLayer.apply(this, arguments); +} +module.exports = BackgroundStyleLayer; +BackgroundStyleLayer.prototype = util.inherit(StyleLayer, {}); +},{"../../util/util":188,"../style_layer":125}],127:[function(require,module,exports){ +'use strict'; +var util = require('../../util/util'); +var StyleLayer = require('../style_layer'); +function CircleStyleLayer() { + StyleLayer.apply(this, arguments); +} +module.exports = CircleStyleLayer; +CircleStyleLayer.prototype = util.inherit(StyleLayer, {}); +},{"../../util/util":188,"../style_layer":125}],128:[function(require,module,exports){ +'use strict'; +var util = require('../../util/util'); +var StyleLayer = require('../style_layer'); +function FillStyleLayer() { + StyleLayer.apply(this, arguments); +} +FillStyleLayer.prototype = util.inherit(StyleLayer, { + getPaintValue: function (name, globalProperties, featureProperties) { + if (name === 'fill-outline-color' && this.getPaintProperty('fill-outline-color') === undefined) { + return StyleLayer.prototype.getPaintValue.call(this, 'fill-color', globalProperties, featureProperties); } else { - callback(new Error(xhr.statusText)); + return StyleLayer.prototype.getPaintValue.call(this, name, globalProperties, featureProperties); } - }; - xhr.send(); - return xhr; -}; - -exports.getArrayBuffer = function(url, callback) { - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, true); - xhr.responseType = 'arraybuffer'; - xhr.onerror = function(e) { - callback(e); - }; - xhr.onload = function() { - if (xhr.status >= 200 && xhr.status < 300 && xhr.response) { - callback(null, xhr.response); + }, + getPaintValueStopZoomLevels: function (name) { + if (name === 'fill-outline-color' && this.getPaintProperty('fill-outline-color') === undefined) { + return StyleLayer.prototype.getPaintValueStopZoomLevels.call(this, 'fill-color'); } else { - callback(new Error(xhr.statusText)); + return StyleLayer.prototype.getPaintValueStopZoomLevels.call(this, name); } - }; - xhr.send(); - return xhr; -}; - -function sameOrigin(url) { - var a = document.createElement('a'); - a.href = url; - return a.protocol === document.location.protocol && a.host === document.location.host; -} - -exports.getImage = function(url, callback) { - return exports.getArrayBuffer(url, function(err, imgData) { - if (err) return callback(err); - var img = new Image(); - img.onload = function() { - callback(null, img); - (window.URL || window.webkitURL).revokeObjectURL(img.src); - }; - var blob = new Blob([new Uint8Array(imgData)], { type: 'image/png' }); - img.src = (window.URL || window.webkitURL).createObjectURL(blob); - img.getData = function() { - var canvas = document.createElement('canvas'); - var context = canvas.getContext('2d'); - canvas.width = img.width; - canvas.height = img.height; - context.drawImage(img, 0, 0); - return context.getImageData(0, 0, img.width, img.height).data; - }; - return img; - }); -}; - -exports.getVideo = function(urls, callback) { - var video = document.createElement('video'); - video.onloadstart = function() { - callback(null, video); - }; - for (var i = 0; i < urls.length; i++) { - var s = document.createElement('source'); - if (!sameOrigin(urls[i])) { - video.crossOrigin = 'Anonymous'; + }, + getPaintInterpolationT: function (name, zoom) { + if (name === 'fill-outline-color' && this.getPaintProperty('fill-outline-color') === undefined) { + return StyleLayer.prototype.getPaintInterpolationT.call(this, 'fill-color', zoom); + } else { + return StyleLayer.prototype.getPaintInterpolationT.call(this, name, zoom); } - s.src = urls[i]; - video.appendChild(s); - } - video.getData = function() { return video; }; - return video; -}; - -},{}],102:[function(require,module,exports){ -'use strict'; - -var Canvas = require('./canvas'); - -/* - * Unlike js/util/browser.js, this code is written with the expectation - * of a browser environment with a global 'window' object - */ - -/** - * Provides a function that outputs milliseconds: either performance.now() - * or a fallback to Date.now() - * @private - */ -module.exports.now = (function() { - if (window.performance && - window.performance.now) { - return window.performance.now.bind(window.performance); - } else { - return Date.now.bind(Date); - } -}()); - -var frame = window.requestAnimationFrame || - window.mozRequestAnimationFrame || - window.webkitRequestAnimationFrame || - window.msRequestAnimationFrame; - -exports.frame = function(fn) { - return frame(fn); -}; - -var cancel = window.cancelAnimationFrame || - window.mozCancelAnimationFrame || - window.webkitCancelAnimationFrame || - window.msCancelAnimationFrame; - -exports.cancelFrame = function(id) { - cancel(id); -}; - -exports.timed = function (fn, dur, ctx) { - if (!dur) { - fn.call(ctx, 1); - return null; - } - - var abort = false, - start = module.exports.now(); - - function tick(now) { - if (abort) return; - now = module.exports.now(); - - if (now >= start + dur) { - fn.call(ctx, 1); + }, + isPaintValueFeatureConstant: function (name) { + if (name === 'fill-outline-color' && this.getPaintProperty('fill-outline-color') === undefined) { + return StyleLayer.prototype.isPaintValueFeatureConstant.call(this, 'fill-color'); } else { - fn.call(ctx, (now - start) / dur); - exports.frame(tick); + return StyleLayer.prototype.isPaintValueFeatureConstant.call(this, name); + } + }, + isPaintValueZoomConstant: function (name) { + if (name === 'fill-outline-color' && this.getPaintProperty('fill-outline-color') === undefined) { + return StyleLayer.prototype.isPaintValueZoomConstant.call(this, 'fill-color'); + } else { + return StyleLayer.prototype.isPaintValueZoomConstant.call(this, name); } } - - exports.frame(tick); - - return function() { abort = true; }; -}; - -exports.supportsWebGL = {}; - -/** - * Test whether the basic JavaScript and DOM features required for Mapbox GL are present. - * @param {Object} options - * @param {boolean} [options.failIfMajorPerformanceCaveat=false] If `true`, map creation will fail if the implementation determines that the performance of the created WebGL context would be dramatically lower than expected. - * @return {boolean} Returns true if Mapbox GL should be expected to work, and false if not. - * @memberof mapboxgl - * @static - */ -exports.supported = function(options) { - - var supports = [ - - function() { return typeof window !== 'undefined'; }, - - function() { return typeof document !== 'undefined'; }, - - function () { - return !!(Array.prototype && - Array.prototype.every && - Array.prototype.filter && - Array.prototype.forEach && - Array.prototype.indexOf && - Array.prototype.lastIndexOf && - Array.prototype.map && - Array.prototype.some && - Array.prototype.reduce && - Array.prototype.reduceRight && - Array.isArray); - }, - - function() { - return !!(Function.prototype && Function.prototype.bind) && - !!(Object.keys && - Object.create && - Object.getPrototypeOf && - Object.getOwnPropertyNames && - Object.isSealed && - Object.isFrozen && - Object.isExtensible && - Object.getOwnPropertyDescriptor && - Object.defineProperty && - Object.defineProperties && - Object.seal && - Object.freeze && - Object.preventExtensions); - }, - - function() { - return 'JSON' in window && 'parse' in JSON && 'stringify' in JSON; - }, - - function() { - var opt = (options && options.failIfMajorPerformanceCaveat) || false, - fimpc = 'fimpc_' + String(opt); - if (exports.supportsWebGL[fimpc] === undefined) { - var canvas = new Canvas(); - exports.supportsWebGL[fimpc] = canvas.supportsWebGLContext(opt); +}); +module.exports = FillStyleLayer; +},{"../../util/util":188,"../style_layer":125}],129:[function(require,module,exports){ +'use strict'; +var util = require('../../util/util'); +var StyleLayer = require('../style_layer'); +function LineStyleLayer() { + StyleLayer.apply(this, arguments); +} +module.exports = LineStyleLayer; +LineStyleLayer.prototype = util.inherit(StyleLayer, { + getPaintValue: function (name, globalProperties, featureProperties) { + var value = StyleLayer.prototype.getPaintValue.apply(this, arguments); + if (value && name === 'line-dasharray') { + var flooredZoom = Math.floor(globalProperties.zoom); + if (this._flooredZoom !== flooredZoom) { + this._flooredZoom = flooredZoom; + this._flooredLineWidth = this.getPaintValue('line-width', globalProperties, featureProperties); } - return exports.supportsWebGL[fimpc]; - }, - - function() { return 'Worker' in window; } - ]; - - for (var i = 0; i < supports.length; i++) { - if (!supports[i]()) return false; + value.fromScale *= this._flooredLineWidth; + value.toScale *= this._flooredLineWidth; + } + return value; } - return true; -}; - -exports.hardwareConcurrency = navigator.hardwareConcurrency || 8; - -Object.defineProperty(exports, 'devicePixelRatio', { - get: function() { return window.devicePixelRatio; } }); - -exports.supportsWebp = false; - -var webpImgTest = document.createElement('img'); -webpImgTest.onload = function() { - exports.supportsWebp = true; -}; -webpImgTest.src = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAQAAAAfQ//73v/+BiOh/AAA='; - -},{"./canvas":103}],103:[function(require,module,exports){ +},{"../../util/util":188,"../style_layer":125}],130:[function(require,module,exports){ 'use strict'; - -var util = require('../util'); - -module.exports = Canvas; - -function Canvas(parent, container) { - this.canvas = document.createElement('canvas'); - - if (parent && container) { - this.canvas.style.position = 'absolute'; - this.canvas.classList.add('mapboxgl-canvas'); - this.canvas.addEventListener('webglcontextlost', parent._contextLost.bind(parent), false); - this.canvas.addEventListener('webglcontextrestored', parent._contextRestored.bind(parent), false); - this.canvas.setAttribute('tabindex', 0); - container.appendChild(this.canvas); - } +var util = require('../../util/util'); +var StyleLayer = require('../style_layer'); +function RasterStyleLayer() { + StyleLayer.apply(this, arguments); } - -Canvas.prototype.resize = function(width, height) { - var pixelRatio = window.devicePixelRatio || 1; - - // Request the required canvas size taking the pixelratio into account. - this.canvas.width = pixelRatio * width; - this.canvas.height = pixelRatio * height; - - // Maintain the same canvas size, potentially downscaling it for HiDPI displays - this.canvas.style.width = width + 'px'; - this.canvas.style.height = height + 'px'; -}; - -var requiredContextAttributes = { - antialias: false, - alpha: true, - stencil: true, - depth: true -}; - -Canvas.prototype.getWebGLContext = function(attributes) { - attributes = util.extend({}, attributes, requiredContextAttributes); - - return this.canvas.getContext('webgl', attributes) || - this.canvas.getContext('experimental-webgl', attributes); -}; - -Canvas.prototype.supportsWebGLContext = function(failIfMajorPerformanceCaveat) { - var attributes = util.extend({ - failIfMajorPerformanceCaveat: failIfMajorPerformanceCaveat - }, requiredContextAttributes); - - if ('probablySupportsContext' in this.canvas) { - return this.canvas.probablySupportsContext('webgl', attributes) || - this.canvas.probablySupportsContext('experimental-webgl', attributes); - } else if ('supportsContext' in this.canvas) { - return this.canvas.supportsContext('webgl', attributes) || - this.canvas.supportsContext('experimental-webgl', attributes); - } - - return !!window.WebGLRenderingContext && !!this.getWebGLContext(failIfMajorPerformanceCaveat); -}; - -Canvas.prototype.getElement = function() { - return this.canvas; -}; - -},{"../util":113}],104:[function(require,module,exports){ +module.exports = RasterStyleLayer; +RasterStyleLayer.prototype = util.inherit(StyleLayer, {}); +},{"../../util/util":188,"../style_layer":125}],131:[function(require,module,exports){ 'use strict'; - -var Actor = require('../actor'); -var WebWorkify = require('webworkify'); - -module.exports = Dispatcher; - -function Dispatcher(length, parent) { - this.actors = []; - this.currentActor = 0; - for (var i = 0; i < length; i++) { - var worker = new WebWorkify(require('../../source/worker')); - var actor = new Actor(worker, parent); - actor.name = "Worker " + i; - this.actors.push(actor); - } +var util = require('../../util/util'); +var StyleLayer = require('../style_layer'); +function SymbolStyleLayer() { + StyleLayer.apply(this, arguments); } - -Dispatcher.prototype = { - broadcast: function(type, data) { - for (var i = 0; i < this.actors.length; i++) { - this.actors[i].send(type, data); - } - }, - - send: function(type, data, callback, targetID, buffers) { - if (typeof targetID !== 'number' || isNaN(targetID)) { - // Use round robin to send requests to web workers. - targetID = this.currentActor = (this.currentActor + 1) % this.actors.length; - } - - this.actors[targetID].send(type, data, callback, buffers); - return targetID; - }, - - remove: function() { - for (var i = 0; i < this.actors.length; i++) { - this.actors[i].target.terminate(); +module.exports = SymbolStyleLayer; +SymbolStyleLayer.prototype = util.inherit(StyleLayer, { + getLayoutValue: function (name, globalProperties, featureProperties) { + var value = StyleLayer.prototype.getLayoutValue.apply(this, arguments); + if (value !== 'auto') { + return value; + } + switch (name) { + case 'text-rotation-alignment': + case 'icon-rotation-alignment': + return this.getLayoutValue('symbol-placement', globalProperties, featureProperties) === 'line' ? 'map' : 'viewport'; + case 'text-pitch-alignment': + return this.getLayoutValue('text-rotation-alignment', globalProperties, featureProperties); + default: + return value; } - this.actors = []; } -}; - -},{"../../source/worker":54,"../actor":100,"webworkify":172}],105:[function(require,module,exports){ +}); +},{"../../util/util":188,"../style_layer":125}],132:[function(require,module,exports){ 'use strict'; - -var Point = require('point-geometry'); - -exports.create = function (tagName, className, container) { - var el = document.createElement(tagName); - if (className) el.className = className; - if (container) container.appendChild(el); - return el; -}; - -var docStyle = document.documentElement.style; - -function testProp(props) { - for (var i = 0; i < props.length; i++) { - if (props[i] in docStyle) { - return props[i]; - } +module.exports = require('mapbox-gl-style-spec/reference/latest.min'); +},{"mapbox-gl-style-spec/reference/latest.min":68}],133:[function(require,module,exports){ +'use strict'; +var util = require('../util/util'); +var interpolate = require('../util/interpolate'); +module.exports = StyleTransition; +function StyleTransition(reference, declaration, oldTransition, value) { + this.declaration = declaration; + this.startTime = this.endTime = new Date().getTime(); + if (reference.function === 'piecewise-constant' && reference.transition) { + this.interp = interpZoomTransitioned; + } else { + this.interp = interpolate[reference.type]; } -} - -var selectProp = testProp(['userSelect', 'MozUserSelect', 'WebkitUserSelect', 'msUserSelect']), - userSelect; -exports.disableDrag = function () { - if (selectProp) { - userSelect = docStyle[selectProp]; - docStyle[selectProp] = 'none'; + this.oldTransition = oldTransition; + this.duration = value.duration || 0; + this.delay = value.delay || 0; + if (!this.instant()) { + this.endTime = this.startTime + this.duration + this.delay; + this.ease = util.easeCubicInOut; } -}; -exports.enableDrag = function () { - if (selectProp) { - docStyle[selectProp] = userSelect; + if (oldTransition && oldTransition.endTime <= this.startTime) { + delete oldTransition.oldTransition; } +} +StyleTransition.prototype.instant = function () { + return !this.oldTransition || !this.interp || this.duration === 0 && this.delay === 0; }; - -var transformProp = testProp(['transform', 'WebkitTransform']); -exports.setTransform = function(el, value) { - el.style[transformProp] = value; +StyleTransition.prototype.calculate = function (globalProperties, featureProperties) { + var value = this.declaration.calculate(util.extend({}, globalProperties, { duration: this.duration }), featureProperties); + if (this.instant()) + return value; + var t = globalProperties.time || Date.now(); + if (t < this.endTime) { + var oldValue = this.oldTransition.calculate(util.extend({}, globalProperties, { time: this.startTime }), featureProperties); + var eased = this.ease((t - this.startTime - this.delay) / this.duration); + value = this.interp(oldValue, value, eased); + } + return value; }; - -// Suppress the next click, but only if it's immediate. -function suppressClick(e) { - e.preventDefault(); - e.stopPropagation(); - window.removeEventListener('click', suppressClick, true); +function interpZoomTransitioned(from, to, t) { + if ((from && from.to) === undefined || (to && to.to) === undefined) { + return undefined; + } else { + return { + from: from.to, + fromScale: from.toScale, + to: to.to, + toScale: to.toScale, + t: t + }; + } } -exports.suppressClick = function() { - window.addEventListener('click', suppressClick, true); - window.setTimeout(function() { - window.removeEventListener('click', suppressClick, true); - }, 0); -}; - -exports.mousePos = function (el, e) { - var rect = el.getBoundingClientRect(); - e = e.touches ? e.touches[0] : e; - return new Point( - e.clientX - rect.left - el.clientLeft, - e.clientY - rect.top - el.clientTop); +},{"../util/interpolate":182,"../util/util":188}],134:[function(require,module,exports){ +'use strict'; +module.exports = require('mapbox-gl-style-spec/lib/validate_style.min'); +module.exports.emitErrors = function (emitter, errors) { + if (errors && errors.length) { + for (var i = 0; i < errors.length; i++) { + emitter.fire('error', { error: new Error(errors[i].message) }); + } + return true; + } else { + return false; + } }; - -},{"point-geometry":162}],106:[function(require,module,exports){ +},{"mapbox-gl-style-spec/lib/validate_style.min":67}],135:[function(require,module,exports){ 'use strict'; - -module.exports = { - API_URL: 'https://api.mapbox.com', - REQUIRE_ACCESS_TOKEN: true +var Point = require('point-geometry'); +module.exports = Anchor; +function Anchor(x, y, angle, segment) { + this.x = x; + this.y = y; + this.angle = angle; + if (segment !== undefined) { + this.segment = segment; + } +} +Anchor.prototype = Object.create(Point.prototype); +Anchor.prototype.clone = function () { + return new Anchor(this.x, this.y, this.angle, this.segment); }; - -},{}],107:[function(require,module,exports){ +},{"point-geometry":196}],136:[function(require,module,exports){ 'use strict'; - -var util = require('./util'); - -/** - * Methods mixed in to other classes for event capabilities. - * @mixin Evented - */ -var Evented = { - - /** - * Subscribe to a specified event with a listener function the latter gets the data object that was passed to `fire` and additionally `target` and `type` properties - * - * @param {string} type Event type - * @param {Function} listener Function to be called when the event is fired - */ - on: function(type, fn) { - this._events = this._events || {}; - this._events[type] = this._events[type] || []; - this._events[type].push(fn); - - return this; - }, - - /** - * Remove a event listener - * - * @param {string} [type] Event type. If none is specified, remove all listeners - * @param {Function} [listener] Function to be called when the event is fired. If none is specified all listeners are removed - */ - off: function(type, fn) { - if (!type) { - // clear all listeners if no arguments specified - delete this._events; - return this; +module.exports = checkMaxAngle; +function checkMaxAngle(line, anchor, labelLength, windowSize, maxAngle) { + if (anchor.segment === undefined) + return true; + var p = anchor; + var index = anchor.segment + 1; + var anchorDistance = 0; + while (anchorDistance > -labelLength / 2) { + index--; + if (index < 0) + return false; + anchorDistance -= line[index].dist(p); + p = line[index]; + } + anchorDistance += line[index].dist(line[index + 1]); + index++; + var recentCorners = []; + var recentAngleDelta = 0; + while (anchorDistance < labelLength / 2) { + var prev = line[index - 1]; + var current = line[index]; + var next = line[index + 1]; + if (!next) + return false; + var angleDelta = prev.angleTo(current) - current.angleTo(next); + angleDelta = Math.abs((angleDelta + 3 * Math.PI) % (Math.PI * 2) - Math.PI); + recentCorners.push({ + distance: anchorDistance, + angleDelta: angleDelta + }); + recentAngleDelta += angleDelta; + while (anchorDistance - recentCorners[0].distance > windowSize) { + recentAngleDelta -= recentCorners.shift().angleDelta; } - - if (!this.listens(type)) return this; - - if (fn) { - var idx = this._events[type].indexOf(fn); - if (idx >= 0) { - this._events[type].splice(idx, 1); + if (recentAngleDelta > maxAngle) + return false; + index++; + anchorDistance += current.dist(next); + } + return true; +} +},{}],137:[function(require,module,exports){ +'use strict'; +var Point = require('point-geometry'); +module.exports = clipLine; +function clipLine(lines, x1, y1, x2, y2) { + var clippedLines = []; + for (var l = 0; l < lines.length; l++) { + var line = lines[l]; + var clippedLine; + for (var i = 0; i < line.length - 1; i++) { + var p0 = line[i]; + var p1 = line[i + 1]; + if (p0.x < x1 && p1.x < x1) { + continue; + } else if (p0.x < x1) { + p0 = new Point(x1, p0.y + (p1.y - p0.y) * ((x1 - p0.x) / (p1.x - p0.x)))._round(); + } else if (p1.x < x1) { + p1 = new Point(x1, p0.y + (p1.y - p0.y) * ((x1 - p0.x) / (p1.x - p0.x)))._round(); } - if (!this._events[type].length) { - delete this._events[type]; + if (p0.y < y1 && p1.y < y1) { + continue; + } else if (p0.y < y1) { + p0 = new Point(p0.x + (p1.x - p0.x) * ((y1 - p0.y) / (p1.y - p0.y)), y1)._round(); + } else if (p1.y < y1) { + p1 = new Point(p0.x + (p1.x - p0.x) * ((y1 - p0.y) / (p1.y - p0.y)), y1)._round(); } - } else { - delete this._events[type]; + if (p0.x >= x2 && p1.x >= x2) { + continue; + } else if (p0.x >= x2) { + p0 = new Point(x2, p0.y + (p1.y - p0.y) * ((x2 - p0.x) / (p1.x - p0.x)))._round(); + } else if (p1.x >= x2) { + p1 = new Point(x2, p0.y + (p1.y - p0.y) * ((x2 - p0.x) / (p1.x - p0.x)))._round(); + } + if (p0.y >= y2 && p1.y >= y2) { + continue; + } else if (p0.y >= y2) { + p0 = new Point(p0.x + (p1.x - p0.x) * ((y2 - p0.y) / (p1.y - p0.y)), y2)._round(); + } else if (p1.y >= y2) { + p1 = new Point(p0.x + (p1.x - p0.x) * ((y2 - p0.y) / (p1.y - p0.y)), y2)._round(); + } + if (!clippedLine || !p0.equals(clippedLine[clippedLine.length - 1])) { + clippedLine = [p0]; + clippedLines.push(clippedLine); + } + clippedLine.push(p1); } - - return this; - }, - - /** - * Call a function once when an event has fired - * - * @param {string} type Event type. - * @param {Function} listener Function to be called once when the event is fired - */ - once: function(type, fn) { - var wrapper = function(data) { - this.off(type, wrapper); - fn.call(this, data); - }.bind(this); - this.on(type, wrapper); - return this; - }, - - /** - * Fire event of a given string type with the given data object - * - * @param {string} type Event type - * @param {Object} [data] Optional data passed to the event receiver (e.g. {@link #EventData}) - * @returns {Object} `this` - */ - fire: function(type, data) { - if (!this.listens(type)) return this; - - data = util.extend({}, data); - util.extend(data, {type: type, target: this}); - - // make sure adding/removing listeners inside other listeners won't cause infinite loop - var listeners = this._events[type].slice(); - - for (var i = 0; i < listeners.length; i++) { - listeners[i].call(this, data); + } + return clippedLines; +} +},{"point-geometry":196}],138:[function(require,module,exports){ +'use strict'; +var StructArrayType = require('../util/struct_array'); +var util = require('../util/util'); +var Point = require('point-geometry'); +var CollisionBoxArray = module.exports = new StructArrayType({ + members: [ + { + type: 'Int16', + name: 'anchorPointX' + }, + { + type: 'Int16', + name: 'anchorPointY' + }, + { + type: 'Int16', + name: 'x1' + }, + { + type: 'Int16', + name: 'y1' + }, + { + type: 'Int16', + name: 'x2' + }, + { + type: 'Int16', + name: 'y2' + }, + { + type: 'Float32', + name: 'maxScale' + }, + { + type: 'Uint32', + name: 'featureIndex' + }, + { + type: 'Uint16', + name: 'sourceLayerIndex' + }, + { + type: 'Uint16', + name: 'bucketIndex' + }, + { + type: 'Int16', + name: 'bbox0' + }, + { + type: 'Int16', + name: 'bbox1' + }, + { + type: 'Int16', + name: 'bbox2' + }, + { + type: 'Int16', + name: 'bbox3' + }, + { + type: 'Float32', + name: 'placementScale' } - - return this; - }, - - /** - * Check if an event is registered to a type - * @param {string} type Event type - * @returns {boolean} `true` if there is at least one registered listener for events of type `type` - */ - listens: function(type) { - return !!(this._events && this._events[type]); + ] +}); +util.extendAll(CollisionBoxArray.prototype.StructType.prototype, { + get anchorPoint() { + return new Point(this.anchorPointX, this.anchorPointY); } -}; - -module.exports = Evented; - -},{"./util":113}],108:[function(require,module,exports){ +}); +},{"../util/struct_array":186,"../util/util":188,"point-geometry":196}],139:[function(require,module,exports){ 'use strict'; - -module.exports = Glyphs; - -function Glyphs(pbf, end) { - this.stacks = pbf.readFields(readFontstacks, [], end); -} - -function readFontstacks(tag, stacks, pbf) { - if (tag === 1) { - var fontstack = pbf.readMessage(readFontstack, {glyphs: {}}); - stacks.push(fontstack); +module.exports = CollisionFeature; +function CollisionFeature(collisionBoxArray, line, anchor, featureIndex, sourceLayerIndex, bucketIndex, shaped, boxScale, padding, alignLine, straight) { + var y1 = shaped.top * boxScale - padding; + var y2 = shaped.bottom * boxScale + padding; + var x1 = shaped.left * boxScale - padding; + var x2 = shaped.right * boxScale + padding; + this.boxStartIndex = collisionBoxArray.length; + if (alignLine) { + var height = y2 - y1; + var length = x2 - x1; + if (height > 0) { + height = Math.max(10 * boxScale, height); + if (straight) { + var vector = line[anchor.segment + 1].sub(line[anchor.segment])._unit()._mult(length); + var straightLine = [ + anchor.sub(vector), + anchor.add(vector) + ]; + this._addLineCollisionBoxes(collisionBoxArray, straightLine, anchor, 0, length, height, featureIndex, sourceLayerIndex, bucketIndex); + } else { + this._addLineCollisionBoxes(collisionBoxArray, line, anchor, anchor.segment, length, height, featureIndex, sourceLayerIndex, bucketIndex); + } + } + } else { + collisionBoxArray.emplaceBack(anchor.x, anchor.y, x1, y1, x2, y2, Infinity, featureIndex, sourceLayerIndex, bucketIndex, 0, 0, 0, 0, 0); } + this.boxEndIndex = collisionBoxArray.length; } - -function readFontstack(tag, fontstack, pbf) { - if (tag === 1) fontstack.name = pbf.readString(); - else if (tag === 2) fontstack.range = pbf.readString(); - else if (tag === 3) { - var glyph = pbf.readMessage(readGlyph, {}); - fontstack.glyphs[glyph.id] = glyph; +CollisionFeature.prototype._addLineCollisionBoxes = function (collisionBoxArray, line, anchor, segment, labelLength, boxSize, featureIndex, sourceLayerIndex, bucketIndex) { + var step = boxSize / 2; + var nBoxes = Math.floor(labelLength / step); + var firstBoxOffset = -boxSize / 2; + var bboxes = this.boxes; + var p = anchor; + var index = segment + 1; + var anchorDistance = firstBoxOffset; + do { + index--; + if (index < 0) + return bboxes; + anchorDistance -= line[index].dist(p); + p = line[index]; + } while (anchorDistance > -labelLength / 2); + var segmentLength = line[index].dist(line[index + 1]); + for (var i = 0; i < nBoxes; i++) { + var boxDistanceToAnchor = -labelLength / 2 + i * step; + while (anchorDistance + segmentLength < boxDistanceToAnchor) { + anchorDistance += segmentLength; + index++; + if (index + 1 >= line.length) + return bboxes; + segmentLength = line[index].dist(line[index + 1]); + } + var segmentBoxDistance = boxDistanceToAnchor - anchorDistance; + var p0 = line[index]; + var p1 = line[index + 1]; + var boxAnchorPoint = p1.sub(p0)._unit()._mult(segmentBoxDistance)._add(p0)._round(); + var distanceToInnerEdge = Math.max(Math.abs(boxDistanceToAnchor - firstBoxOffset) - step / 2, 0); + var maxScale = labelLength / 2 / distanceToInnerEdge; + collisionBoxArray.emplaceBack(boxAnchorPoint.x, boxAnchorPoint.y, -boxSize / 2, -boxSize / 2, boxSize / 2, boxSize / 2, maxScale, featureIndex, sourceLayerIndex, bucketIndex, 0, 0, 0, 0, 0); } -} - -function readGlyph(tag, glyph, pbf) { - if (tag === 1) glyph.id = pbf.readVarint(); - else if (tag === 2) glyph.bitmap = pbf.readBytes(); - else if (tag === 3) glyph.width = pbf.readVarint(); - else if (tag === 4) glyph.height = pbf.readVarint(); - else if (tag === 5) glyph.left = pbf.readSVarint(); - else if (tag === 6) glyph.top = pbf.readSVarint(); - else if (tag === 7) glyph.advance = pbf.readVarint(); -} - -},{}],109:[function(require,module,exports){ -'use strict'; - -module.exports = interpolate; - -function interpolate(a, b, t) { - return (a * (1 - t)) + (b * t); -} - -interpolate.number = interpolate; - -interpolate.vec2 = function(from, to, t) { - return [ - interpolate(from[0], to[0], t), - interpolate(from[1], to[1], t) - ]; -}; - -/* - * Interpolate between two colors given as 4-element arrays. - * - * @param {Color} from - * @param {Color} to - * @param {number} t interpolation factor between 0 and 1 - * @returns {Color} interpolated color - */ -interpolate.color = function(from, to, t) { - return [ - interpolate(from[0], to[0], t), - interpolate(from[1], to[1], t), - interpolate(from[2], to[2], t), - interpolate(from[3], to[3], t) - ]; -}; - -interpolate.array = function(from, to, t) { - return from.map(function(d, i) { - return interpolate(d, to[i], t); - }); + return bboxes; }; - -},{}],110:[function(require,module,exports){ +},{}],140:[function(require,module,exports){ 'use strict'; - -var config = require('./config'); -var browser = require('./browser'); - -function normalizeURL(url, pathPrefix, accessToken) { - accessToken = accessToken || config.ACCESS_TOKEN; - - if (!accessToken && config.REQUIRE_ACCESS_TOKEN) { - throw new Error('An API access token is required to use Mapbox GL. ' + - 'See https://www.mapbox.com/developers/api/#access-tokens'); +var Point = require('point-geometry'); +var EXTENT = require('../data/bucket').EXTENT; +var Grid = require('grid-index'); +module.exports = CollisionTile; +function CollisionTile(angle, pitch, collisionBoxArray) { + if (typeof angle === 'object') { + var serialized = angle; + collisionBoxArray = pitch; + angle = serialized.angle; + pitch = serialized.pitch; + this.grid = new Grid(serialized.grid); + this.ignoredGrid = new Grid(serialized.ignoredGrid); + } else { + this.grid = new Grid(EXTENT, 12, 6); + this.ignoredGrid = new Grid(EXTENT, 12, 0); } - - url = url.replace(/^mapbox:\/\//, config.API_URL + pathPrefix); - url += url.indexOf('?') !== -1 ? '&access_token=' : '?access_token='; - - if (config.REQUIRE_ACCESS_TOKEN) { - if (accessToken[0] === 's') { - throw new Error('Use a public access token (pk.*) with Mapbox GL JS, not a secret access token (sk.*). ' + - 'See https://www.mapbox.com/developers/api/#access-tokens'); - } - - url += accessToken; + this.angle = angle; + this.pitch = pitch; + var sin = Math.sin(angle), cos = Math.cos(angle); + this.rotationMatrix = [ + cos, + -sin, + sin, + cos + ]; + this.reverseRotationMatrix = [ + cos, + sin, + -sin, + cos + ]; + this.yStretch = 1 / Math.cos(pitch / 180 * Math.PI); + this.yStretch = Math.pow(this.yStretch, 1.3); + this.collisionBoxArray = collisionBoxArray; + if (collisionBoxArray.length === 0) { + collisionBoxArray.emplaceBack(); + var maxInt16 = 32767; + collisionBoxArray.emplaceBack(0, 0, 0, -maxInt16, 0, maxInt16, maxInt16, 0, 0, 0, 0, 0, 0, 0, 0, 0); + collisionBoxArray.emplaceBack(EXTENT, 0, 0, -maxInt16, 0, maxInt16, maxInt16, 0, 0, 0, 0, 0, 0, 0, 0, 0); + collisionBoxArray.emplaceBack(0, 0, -maxInt16, 0, maxInt16, 0, maxInt16, 0, 0, 0, 0, 0, 0, 0, 0, 0); + collisionBoxArray.emplaceBack(0, EXTENT, -maxInt16, 0, maxInt16, 0, maxInt16, 0, 0, 0, 0, 0, 0, 0, 0, 0); } - - return url; + this.tempCollisionBox = collisionBoxArray.get(0); + this.edges = [ + collisionBoxArray.get(1), + collisionBoxArray.get(2), + collisionBoxArray.get(3), + collisionBoxArray.get(4) + ]; } - -module.exports.normalizeStyleURL = function(url, accessToken) { - if (!url.match(/^mapbox:\/\/styles\//)) - return url; - - var split = url.split('/'); - var user = split[3]; - var style = split[4]; - var draft = split[5] ? '/draft' : ''; - return normalizeURL('mapbox://' + user + '/' + style + draft, '/styles/v1/', accessToken); +CollisionTile.prototype.serialize = function () { + var data = { + angle: this.angle, + pitch: this.pitch, + grid: this.grid.toArrayBuffer(), + ignoredGrid: this.ignoredGrid.toArrayBuffer() + }; + return { + data: data, + transferables: [ + data.grid, + data.ignoredGrid + ] + }; }; - -module.exports.normalizeSourceURL = function(url, accessToken) { - if (!url.match(/^mapbox:\/\//)) - return url; - - // TileJSON requests need a secure flag appended to their URLs so - // that the server knows to send SSL-ified resource references. - return normalizeURL(url + '.json', '/v4/', accessToken) + '&secure'; +CollisionTile.prototype.minScale = 0.25; +CollisionTile.prototype.maxScale = 2; +CollisionTile.prototype.placeCollisionFeature = function (collisionFeature, allowOverlap, avoidEdges) { + var collisionBoxArray = this.collisionBoxArray; + var minPlacementScale = this.minScale; + var rotationMatrix = this.rotationMatrix; + var yStretch = this.yStretch; + for (var b = collisionFeature.boxStartIndex; b < collisionFeature.boxEndIndex; b++) { + var box = collisionBoxArray.get(b); + var anchorPoint = box.anchorPoint._matMult(rotationMatrix); + var x = anchorPoint.x; + var y = anchorPoint.y; + var x1 = x + box.x1; + var y1 = y + box.y1 * yStretch; + var x2 = x + box.x2; + var y2 = y + box.y2 * yStretch; + box.bbox0 = x1; + box.bbox1 = y1; + box.bbox2 = x2; + box.bbox3 = y2; + if (!allowOverlap) { + var blockingBoxes = this.grid.query(x1, y1, x2, y2); + for (var i = 0; i < blockingBoxes.length; i++) { + var blocking = collisionBoxArray.get(blockingBoxes[i]); + var blockingAnchorPoint = blocking.anchorPoint._matMult(rotationMatrix); + minPlacementScale = this.getPlacementScale(minPlacementScale, anchorPoint, box, blockingAnchorPoint, blocking); + if (minPlacementScale >= this.maxScale) { + return minPlacementScale; + } + } + } + if (avoidEdges) { + var rotatedCollisionBox; + if (this.angle) { + var reverseRotationMatrix = this.reverseRotationMatrix; + var tl = new Point(box.x1, box.y1).matMult(reverseRotationMatrix); + var tr = new Point(box.x2, box.y1).matMult(reverseRotationMatrix); + var bl = new Point(box.x1, box.y2).matMult(reverseRotationMatrix); + var br = new Point(box.x2, box.y2).matMult(reverseRotationMatrix); + rotatedCollisionBox = this.tempCollisionBox; + rotatedCollisionBox.anchorPointX = box.anchorPoint.x; + rotatedCollisionBox.anchorPointY = box.anchorPoint.y; + rotatedCollisionBox.x1 = Math.min(tl.x, tr.x, bl.x, br.x); + rotatedCollisionBox.y1 = Math.min(tl.y, tr.x, bl.x, br.x); + rotatedCollisionBox.x2 = Math.max(tl.x, tr.x, bl.x, br.x); + rotatedCollisionBox.y2 = Math.max(tl.y, tr.x, bl.x, br.x); + rotatedCollisionBox.maxScale = box.maxScale; + } else { + rotatedCollisionBox = box; + } + for (var k = 0; k < this.edges.length; k++) { + var edgeBox = this.edges[k]; + minPlacementScale = this.getPlacementScale(minPlacementScale, box.anchorPoint, rotatedCollisionBox, edgeBox.anchorPoint, edgeBox); + if (minPlacementScale >= this.maxScale) { + return minPlacementScale; + } + } + } + } + return minPlacementScale; }; - -module.exports.normalizeGlyphsURL = function(url, accessToken) { - if (!url.match(/^mapbox:\/\//)) - return url; - - var user = url.split('/')[3]; - return normalizeURL('mapbox://' + user + '/{fontstack}/{range}.pbf', '/fonts/v1/', accessToken); +CollisionTile.prototype.queryRenderedSymbols = function (minX, minY, maxX, maxY, scale) { + var sourceLayerFeatures = {}; + var result = []; + var collisionBoxArray = this.collisionBoxArray; + var rotationMatrix = this.rotationMatrix; + var anchorPoint = new Point(minX, minY)._matMult(rotationMatrix); + var queryBox = this.tempCollisionBox; + queryBox.anchorX = anchorPoint.x; + queryBox.anchorY = anchorPoint.y; + queryBox.x1 = 0; + queryBox.y1 = 0; + queryBox.x2 = maxX - minX; + queryBox.y2 = maxY - minY; + queryBox.maxScale = scale; + scale = queryBox.maxScale; + var searchBox = [ + anchorPoint.x + queryBox.x1 / scale, + anchorPoint.y + queryBox.y1 / scale * this.yStretch, + anchorPoint.x + queryBox.x2 / scale, + anchorPoint.y + queryBox.y2 / scale * this.yStretch + ]; + var blockingBoxKeys = this.grid.query(searchBox[0], searchBox[1], searchBox[2], searchBox[3]); + var blockingBoxKeys2 = this.ignoredGrid.query(searchBox[0], searchBox[1], searchBox[2], searchBox[3]); + for (var k = 0; k < blockingBoxKeys2.length; k++) { + blockingBoxKeys.push(blockingBoxKeys2[k]); + } + for (var i = 0; i < blockingBoxKeys.length; i++) { + var blocking = collisionBoxArray.get(blockingBoxKeys[i]); + var sourceLayer = blocking.sourceLayerIndex; + var featureIndex = blocking.featureIndex; + if (sourceLayerFeatures[sourceLayer] === undefined) { + sourceLayerFeatures[sourceLayer] = {}; + } + if (!sourceLayerFeatures[sourceLayer][featureIndex]) { + var blockingAnchorPoint = blocking.anchorPoint.matMult(rotationMatrix); + var minPlacementScale = this.getPlacementScale(this.minScale, anchorPoint, queryBox, blockingAnchorPoint, blocking); + if (minPlacementScale >= scale) { + sourceLayerFeatures[sourceLayer][featureIndex] = true; + result.push(blockingBoxKeys[i]); + } + } + } + return result; }; - -module.exports.normalizeSpriteURL = function(url, format, ext, accessToken) { - if (!url.match(/^mapbox:\/\/sprites\//)) - return url + format + ext; - - var split = url.split('/'); - var user = split[3]; - var style = split[4]; - var draft = split[5] ? '/draft' : ''; - return normalizeURL('mapbox://' + user + '/' + style + draft + '/sprite' + format + ext, '/styles/v1/', accessToken); +CollisionTile.prototype.getPlacementScale = function (minPlacementScale, anchorPoint, box, blockingAnchorPoint, blocking) { + var anchorDiffX = anchorPoint.x - blockingAnchorPoint.x; + var anchorDiffY = anchorPoint.y - blockingAnchorPoint.y; + var s1 = (blocking.x1 - box.x2) / anchorDiffX; + var s2 = (blocking.x2 - box.x1) / anchorDiffX; + var s3 = (blocking.y1 - box.y2) * this.yStretch / anchorDiffY; + var s4 = (blocking.y2 - box.y1) * this.yStretch / anchorDiffY; + if (isNaN(s1) || isNaN(s2)) + s1 = s2 = 1; + if (isNaN(s3) || isNaN(s4)) + s3 = s4 = 1; + var collisionFreeScale = Math.min(Math.max(s1, s2), Math.max(s3, s4)); + var blockingMaxScale = blocking.maxScale; + var boxMaxScale = box.maxScale; + if (collisionFreeScale > blockingMaxScale) { + collisionFreeScale = blockingMaxScale; + } + if (collisionFreeScale > boxMaxScale) { + collisionFreeScale = boxMaxScale; + } + if (collisionFreeScale > minPlacementScale && collisionFreeScale >= blocking.placementScale) { + minPlacementScale = collisionFreeScale; + } + return minPlacementScale; }; - -module.exports.normalizeTileURL = function(url, sourceUrl) { - if (!sourceUrl || !sourceUrl.match(/^mapbox:\/\//)) - return url; - - url = url.replace(/([?&]access_token=)tk\.[^&]+/, '$1' + config.ACCESS_TOKEN); - var extension = browser.supportsWebp ? 'webp' : '$1'; - return url.replace(/\.((?:png|jpg)\d*)(?=$|\?)/, browser.devicePixelRatio >= 2 ? '@2x.' + extension : '.' + extension); +CollisionTile.prototype.insertCollisionFeature = function (collisionFeature, minPlacementScale, ignorePlacement) { + var grid = ignorePlacement ? this.ignoredGrid : this.grid; + var collisionBoxArray = this.collisionBoxArray; + for (var k = collisionFeature.boxStartIndex; k < collisionFeature.boxEndIndex; k++) { + var box = collisionBoxArray.get(k); + box.placementScale = minPlacementScale; + if (minPlacementScale < this.maxScale) { + grid.insert(k, box.bbox0, box.bbox1, box.bbox2, box.bbox3); + } + } }; - -},{"./browser":102,"./config":106}],111:[function(require,module,exports){ +},{"../data/bucket":72,"grid-index":39,"point-geometry":196}],141:[function(require,module,exports){ 'use strict'; - -/** - * A [most-recently-used cache](http://en.wikipedia.org/wiki/Cache_algorithms) - * with hash lookup made possible by keeping a list of keys in parallel to - * an array of dictionary of values - * - * @param {number} max number of permitted values - * @param {Function} onRemove callback called with items when they expire - * @private - */ -module.exports = MRUCache; -function MRUCache(max, onRemove) { - this.max = max; - this.onRemove = onRemove; - this.reset(); +var interpolate = require('../util/interpolate'); +var Anchor = require('../symbol/anchor'); +var checkMaxAngle = require('./check_max_angle'); +module.exports = getAnchors; +function getAnchors(line, spacing, maxAngle, shapedText, shapedIcon, glyphSize, boxScale, overscaling, tileExtent) { + var angleWindowSize = shapedText ? 3 / 5 * glyphSize * boxScale : 0; + var labelLength = Math.max(shapedText ? shapedText.right - shapedText.left : 0, shapedIcon ? shapedIcon.right - shapedIcon.left : 0); + var isLineContinued = line[0].x === 0 || line[0].x === tileExtent || line[0].y === 0 || line[0].y === tileExtent; + if (spacing - labelLength * boxScale < spacing / 4) { + spacing = labelLength * boxScale + spacing / 4; + } + var fixedExtraOffset = glyphSize * 2; + var offset = !isLineContinued ? (labelLength / 2 + fixedExtraOffset) * boxScale * overscaling % spacing : spacing / 2 * overscaling % spacing; + return resample(line, offset, spacing, angleWindowSize, maxAngle, labelLength * boxScale, isLineContinued, false, tileExtent); } - -/** - * Clear the cache - * - * @returns {MRUCache} this cache - * @private - */ -MRUCache.prototype.reset = function() { - for (var key in this.list) { - this.onRemove(this.list[key]); +function resample(line, offset, spacing, angleWindowSize, maxAngle, labelLength, isLineContinued, placeAtMiddle, tileExtent) { + var halfLabelLength = labelLength / 2; + var lineLength = 0; + for (var k = 0; k < line.length - 1; k++) { + lineLength += line[k].dist(line[k + 1]); } - - this.list = {}; - this.order = []; - - return this; -}; - -/** - * Add a key, value combination to the cache, trimming its size if this pushes - * it over max length. - * - * @param {string} key lookup key for the item - * @param {*} data any value - * - * @returns {MRUCache} this cache - * @private - */ -MRUCache.prototype.add = function(key, data) { - this.list[key] = data; - this.order.push(key); - - if (this.order.length > this.max) { - var removedData = this.get(this.order[0]); - if (removedData) this.onRemove(removedData); + var distance = 0, markedDistance = offset - spacing; + var anchors = []; + for (var i = 0; i < line.length - 1; i++) { + var a = line[i], b = line[i + 1]; + var segmentDist = a.dist(b), angle = b.angleTo(a); + while (markedDistance + spacing < distance + segmentDist) { + markedDistance += spacing; + var t = (markedDistance - distance) / segmentDist, x = interpolate(a.x, b.x, t), y = interpolate(a.y, b.y, t); + if (x >= 0 && x < tileExtent && y >= 0 && y < tileExtent && markedDistance - halfLabelLength >= 0 && markedDistance + halfLabelLength <= lineLength) { + var anchor = new Anchor(x, y, angle, i)._round(); + if (!angleWindowSize || checkMaxAngle(line, anchor, labelLength, angleWindowSize, maxAngle)) { + anchors.push(anchor); + } + } + } + distance += segmentDist; } - - return this; -}; - -/** - * Determine whether the value attached to `key` is present - * - * @param {string} key the key to be looked-up - * @returns {boolean} whether the cache has this value - * @private - */ -MRUCache.prototype.has = function(key) { - return key in this.list; -}; - -/** - * List all keys in the cache - * - * @returns {Array} an array of keys in this cache. - * @private - */ -MRUCache.prototype.keys = function() { - return this.order; -}; - -/** - * Get the value attached to a specific key. If the key is not found, - * returns `null` - * - * @param {string} key the key to look up - * @returns {*} the data, or null if it isn't found - * @private - */ -MRUCache.prototype.get = function(key) { - if (!this.has(key)) { return null; } - - var data = this.list[key]; - - delete this.list[key]; - this.order.splice(this.order.indexOf(key), 1); - - return data; -}; - -},{}],112:[function(require,module,exports){ -'use strict'; - -module.exports = resolveTokens; - -/** - * Replace tokens in a string template with values in an object - * - * @param {Object} properties a key/value relationship between tokens and replacements - * @param {string} text the template string - * @returns {string} the template with tokens replaced - * @private - */ -function resolveTokens(properties, text) { - return text.replace(/{([^{}()\[\]<>$=:;.,^]+)}/g, function(match, key) { - return key in properties ? properties[key] : ''; - }); + if (!placeAtMiddle && !anchors.length && !isLineContinued) { + anchors = resample(line, distance / 2, spacing, angleWindowSize, maxAngle, labelLength, isLineContinued, true, tileExtent); + } + return anchors; } - -},{}],113:[function(require,module,exports){ +},{"../symbol/anchor":135,"../util/interpolate":182,"./check_max_angle":136}],142:[function(require,module,exports){ 'use strict'; - -var UnitBezier = require('unitbezier'); -var Coordinate = require('../geo/coordinate'); - -/** - * Given a value `t` that varies between 0 and 1, return - * an interpolation function that eases between 0 and 1 in a pleasing - * cubic in-out fashion. - * - * @param {number} t input - * @returns {number} input - * @private - */ -exports.easeCubicInOut = function (t) { - if (t <= 0) return 0; - if (t >= 1) return 1; - var t2 = t * t, - t3 = t2 * t; - return 4 * (t < 0.5 ? t3 : 3 * (t - t2) + t3 - 0.75); -}; - -/** - * Given given (x, y), (x1, y1) control points for a bezier curve, - * return a function that interpolates along that curve. - * - * @param {number} p1x control point 1 x coordinate - * @param {number} p1y control point 1 y coordinate - * @param {number} p2x control point 2 x coordinate - * @param {number} p2y control point 2 y coordinate - * @returns {Function} interpolator: receives number value, returns - * number value. - * @private - */ -exports.bezier = function(p1x, p1y, p2x, p2y) { - var bezier = new UnitBezier(p1x, p1y, p2x, p2y); - return function(t) { - return bezier.solve(t); - }; -}; - -/** - * A default bezier-curve powered easing function with - * control points (0.25, 0.1) and (0.25, 1) - * - * @param {number} t - * @returns {number} output - * @private - */ -exports.ease = exports.bezier(0.25, 0.1, 0.25, 1); - -/** - * Given a four-element array of numbers that represents a color in - * RGBA, return a version for which the RGB components are multiplied - * by the A (alpha) component - * - * @param {Array} color color array - * @param {number} [additionalOpacity] additional opacity to be multiplied into - * the color's alpha component. - * @returns {Array} premultiplied color array - * @private - */ -exports.premultiply = function (color, additionalOpacity) { - if (!color) return null; - var opacity = color[3] * additionalOpacity; - return [ - color[0] * opacity, - color[1] * opacity, - color[2] * opacity, - opacity - ]; -}; - -/** - * constrain n to the given range via min + max - * - * @param {number} n value - * @param {number} min the minimum value to be returned - * @param {number} max the maximum value to be returned - * @returns {number} the clamped value - * @private - */ -exports.clamp = function (n, min, max) { - return Math.min(max, Math.max(min, n)); -}; - -/* - * constrain n to the given range, excluding the minimum, via modular arithmetic - * @param {number} n value - * @param {number} min the minimum value to be returned, exclusive - * @param {number} max the maximum value to be returned, inclusive - * @returns {number} constrained number - * @private - */ -exports.wrap = function (n, min, max) { - var d = max - min; - var w = ((n - min) % d + d) % d + min; - return (w === min) ? max : w; -}; - -/* - * return the first non-null and non-undefined argument to this function. - * @returns {*} argument - * @private - */ -exports.coalesce = function() { - for (var i = 0; i < arguments.length; i++) { - var arg = arguments[i]; - if (arg !== null && arg !== undefined) - return arg; +var ShelfPack = require('shelf-pack'); +var util = require('../util/util'); +var SIZE_GROWTH_RATE = 4; +var DEFAULT_SIZE = 128; +var MAX_SIZE = 2048; +module.exports = GlyphAtlas; +function GlyphAtlas() { + this.width = DEFAULT_SIZE; + this.height = DEFAULT_SIZE; + this.bin = new ShelfPack(this.width, this.height); + this.index = {}; + this.ids = {}; + this.data = new Uint8Array(this.width * this.height); +} +GlyphAtlas.prototype.getGlyphs = function () { + var glyphs = {}, split, name, id; + for (var key in this.ids) { + split = key.split('#'); + name = split[0]; + id = split[1]; + if (!glyphs[name]) + glyphs[name] = []; + glyphs[name].push(id); } + return glyphs; }; - -/* - * Call an asynchronous function on an array of arguments, - * calling `callback` with the completed results of all calls. - * - * @param {Array<*>} array input to each call of the async function. - * @param {Function} fn an async function with signature (data, callback) - * @param {Function} callback a callback run after all async work is done. - * called with an array, containing the results of each async call. - * @returns {undefined} - * @private - */ -exports.asyncAll = function (array, fn, callback) { - if (!array.length) { return callback(null, []); } - var remaining = array.length; - var results = new Array(array.length); - var error = null; - array.forEach(function (item, i) { - fn(item, function (err, result) { - if (err) error = err; - results[i] = result; - if (--remaining === 0) callback(error, results); - }); - }); +GlyphAtlas.prototype.getRects = function () { + var rects = {}, split, name, id; + for (var key in this.ids) { + split = key.split('#'); + name = split[0]; + id = split[1]; + if (!rects[name]) + rects[name] = {}; + rects[name][id] = this.index[key]; + } + return rects; }; - -/* - * Compute the difference between the keys in one object and the keys - * in another object. - * - * @param {Object} obj - * @param {Object} other - * @returns {Array} keys difference - * @private - */ -exports.keysDifference = function (obj, other) { - var difference = []; - for (var i in obj) { - if (!(i in other)) { - difference.push(i); +GlyphAtlas.prototype.addGlyph = function (id, name, glyph, buffer) { + if (!glyph) + return null; + var key = name + '#' + glyph.id; + if (this.index[key]) { + if (this.ids[key].indexOf(id) < 0) { + this.ids[key].push(id); } + return this.index[key]; } - return difference; -}; - -/** - * Given a destination object and optionally many source objects, - * copy all properties from the source objects into the destination. - * The last source object given overrides properties from previous - * source objects. - * @param {Object} dest destination object - * @param {...Object} sources sources from which properties are pulled - * @returns {Object} dest - * @private - */ -exports.extend = function (dest) { - for (var i = 1; i < arguments.length; i++) { - var src = arguments[i]; - for (var k in src) { - dest[k] = src[k]; + if (!glyph.bitmap) { + return null; + } + var bufferedWidth = glyph.width + buffer * 2; + var bufferedHeight = glyph.height + buffer * 2; + var padding = 1; + var packWidth = bufferedWidth + 2 * padding; + var packHeight = bufferedHeight + 2 * padding; + packWidth += 4 - packWidth % 4; + packHeight += 4 - packHeight % 4; + var rect = this.bin.packOne(packWidth, packHeight); + if (!rect) { + this.resize(); + rect = this.bin.packOne(packWidth, packHeight); + } + if (!rect) { + util.warnOnce('glyph bitmap overflow'); + return null; + } + this.index[key] = rect; + this.ids[key] = [id]; + var target = this.data; + var source = glyph.bitmap; + for (var y = 0; y < bufferedHeight; y++) { + var y1 = this.width * (rect.y + y + padding) + rect.x + padding; + var y2 = bufferedWidth * y; + for (var x = 0; x < bufferedWidth; x++) { + target[y1 + x] = source[y2 + x]; } } - return dest; + this.dirty = true; + return rect; }; - -/** - * Extend a destination object with all properties of the src object, - * using defineProperty instead of simple assignment. - * @param {Object} dest - * @param {Object} src - * @returns {Object} dest - * @private - */ -exports.extendAll = function (dest, src) { - for (var i in src) { - Object.defineProperty(dest, i, Object.getOwnPropertyDescriptor(src, i)); +GlyphAtlas.prototype.resize = function () { + var prevWidth = this.width; + var prevHeight = this.height; + if (prevWidth >= MAX_SIZE || prevHeight >= MAX_SIZE) + return; + if (this.texture) { + if (this.gl) { + this.gl.deleteTexture(this.texture); + } + this.texture = null; } - return dest; -}; - -/** - * Extend a parent's prototype with all properties in a properties - * object. - * - * @param {Object} parent - * @param {Object} props - * @returns {Object} - * @private - */ -exports.inherit = function (parent, props) { - var parentProto = typeof parent === 'function' ? parent.prototype : parent, - proto = Object.create(parentProto); - exports.extendAll(proto, props); - return proto; + this.width *= SIZE_GROWTH_RATE; + this.height *= SIZE_GROWTH_RATE; + this.bin.resize(this.width, this.height); + var buf = new ArrayBuffer(this.width * this.height); + for (var i = 0; i < prevHeight; i++) { + var src = new Uint8Array(this.data.buffer, prevHeight * i, prevWidth); + var dst = new Uint8Array(buf, prevHeight * i * SIZE_GROWTH_RATE, prevWidth); + dst.set(src); + } + this.data = new Uint8Array(buf); }; - -/** - * Given an object and a number of properties as strings, return version - * of that object with only those properties. - * - * @param {Object} src the object - * @param {Array} properties an array of property names chosen - * to appear on the resulting object. - * @returns {Object} object with limited properties. - * @example - * var foo = { name: 'Charlie', age: 10 }; - * var justName = pick(foo, ['name']); - * // justName = { name: 'Charlie' } - * @private - */ -exports.pick = function (src, properties) { - var result = {}; - for (var i = 0; i < properties.length; i++) { - var k = properties[i]; - if (k in src) { - result[k] = src[k]; - } +GlyphAtlas.prototype.bind = function (gl) { + this.gl = gl; + if (!this.texture) { + this.texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this.texture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.ALPHA, this.width, this.height, 0, gl.ALPHA, gl.UNSIGNED_BYTE, null); + } else { + gl.bindTexture(gl.TEXTURE_2D, this.texture); } - return result; }; - -var id = 1; - -/** - * Return a unique numeric id, starting at 1 and incrementing with - * each call. - * - * @returns {number} unique numeric id. - * @private - */ -exports.uniqueId = function () { - return id++; +GlyphAtlas.prototype.updateTexture = function (gl) { + this.bind(gl); + if (this.dirty) { + gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, this.width, this.height, gl.ALPHA, gl.UNSIGNED_BYTE, this.data); + this.dirty = false; + } }; - -/** - * Create a version of `fn` that only fires once every `time` millseconds. - * - * @param {Function} fn the function to be throttled - * @param {number} time millseconds required between function calls - * @param {*} context the value of `this` with which the function is called - * @returns {Function} debounced function - * @private - */ -exports.throttle = function (fn, time, context) { - var lock, args, wrapperFn, later; - - later = function () { - // reset lock and call if queued - lock = false; - if (args) { - wrapperFn.apply(context, args); - args = false; - } - }; - - wrapperFn = function () { - if (lock) { - // called too soon, queue to call later - args = arguments; - +},{"../util/util":188,"shelf-pack":203}],143:[function(require,module,exports){ +'use strict'; +var normalizeURL = require('../util/mapbox').normalizeGlyphsURL; +var ajax = require('../util/ajax'); +var Glyphs = require('../util/glyphs'); +var GlyphAtlas = require('../symbol/glyph_atlas'); +var Protobuf = require('pbf'); +module.exports = GlyphSource; +function GlyphSource(url) { + this.url = url && normalizeURL(url); + this.atlases = {}; + this.stacks = {}; + this.loading = {}; +} +GlyphSource.prototype.getSimpleGlyphs = function (fontstack, glyphIDs, uid, callback) { + if (this.stacks[fontstack] === undefined) { + this.stacks[fontstack] = {}; + } + if (this.atlases[fontstack] === undefined) { + this.atlases[fontstack] = new GlyphAtlas(); + } + var glyphs = {}; + var stack = this.stacks[fontstack]; + var atlas = this.atlases[fontstack]; + var buffer = 3; + var missing = {}; + var remaining = 0; + var range; + for (var i = 0; i < glyphIDs.length; i++) { + var glyphID = glyphIDs[i]; + range = Math.floor(glyphID / 256); + if (stack[range]) { + var glyph = stack[range].glyphs[glyphID]; + var rect = atlas.addGlyph(uid, fontstack, glyph, buffer); + if (glyph) + glyphs[glyphID] = new SimpleGlyph(glyph, rect, buffer); } else { - // call and lock until later - fn.apply(context, arguments); - setTimeout(later, time); - lock = true; + if (missing[range] === undefined) { + missing[range] = []; + remaining++; + } + missing[range].push(glyphID); } - }; - - return wrapperFn; -}; - -/** - * Create a version of `fn` that is only called `time` milliseconds - * after its last invocation - * - * @param {Function} fn the function to be debounced - * @param {number} time millseconds after which the function will be invoked - * @returns {Function} debounced function - * @private - */ -exports.debounce = function(fn, time) { - var timer, args; - - return function() { - args = arguments; - clearTimeout(timer); - - timer = setTimeout(function() { - fn.apply(null, args); - }, time); - }; -}; - -/** - * Given an array of member function names as strings, replace all of them - * with bound versions that will always refer to `context` as `this`. This - * is useful for classes where otherwise event bindings would reassign - * `this` to the evented object or some other value: this lets you ensure - * the `this` value always. - * - * @param {Array} fns list of member function names - * @param {*} context the context value - * @returns {undefined} changes functions in-place - * @example - * function MyClass() { - * bindAll(['ontimer'], this); - * this.name = 'Tom'; - * } - * MyClass.prototype.ontimer = function() { - * alert(this.name); - * }; - * var myClass = new MyClass(); - * setTimeout(myClass.ontimer, 100); - * @private - */ -exports.bindAll = function(fns, context) { - fns.forEach(function(fn) { - context[fn] = context[fn].bind(context); - }); -}; - -/** - * Given a class, bind all of the methods that look like handlers: that - * begin with _on, and bind them to the class. - * - * @param {Object} context an object with methods - * @private - */ -exports.bindHandlers = function(context) { - for (var i in context) { - if (typeof context[i] === 'function' && i.indexOf('_on') === 0) { - context[i] = context[i].bind(context); + } + if (!remaining) + callback(undefined, glyphs, fontstack); + var onRangeLoaded = function (err, range, data) { + if (!err) { + var stack = this.stacks[fontstack][range] = data.stacks[0]; + for (var i = 0; i < missing[range].length; i++) { + var glyphID = missing[range][i]; + var glyph = stack.glyphs[glyphID]; + var rect = atlas.addGlyph(uid, fontstack, glyph, buffer); + if (glyph) + glyphs[glyphID] = new SimpleGlyph(glyph, rect, buffer); + } } + remaining--; + if (!remaining) + callback(undefined, glyphs, fontstack); + }.bind(this); + for (var r in missing) { + this.loadRange(fontstack, r, onRangeLoaded); } }; - -/** - * Set the 'options' property on `obj` with properties - * from the `options` argument. Properties in the `options` - * object will override existing properties. - * - * @param {Object} obj destination object - * @param {Object} options object of override options - * @returns {Object} derived options object. - * @private - */ -exports.setOptions = function(obj, options) { - if (!obj.hasOwnProperty('options')) { - obj.options = obj.options ? Object.create(obj.options) : {}; - } - for (var i in options) { - obj.options[i] = options[i]; +function SimpleGlyph(glyph, rect, buffer) { + var padding = 1; + this.advance = glyph.advance; + this.left = glyph.left - buffer - padding; + this.top = glyph.top + buffer + padding; + this.rect = rect; +} +GlyphSource.prototype.loadRange = function (fontstack, range, callback) { + if (range * 256 > 65535) + return callback('glyphs > 65535 not supported'); + if (this.loading[fontstack] === undefined) { + this.loading[fontstack] = {}; } - return obj.options; -}; - -/** - * Given a list of coordinates, get their center as a coordinate. - * @param {Array} coords - * @returns {Coordinate} centerpoint - * @private - */ -exports.getCoordinatesCenter = function(coords) { - var minX = Infinity; - var minY = Infinity; - var maxX = -Infinity; - var maxY = -Infinity; - - for (var i = 0; i < coords.length; i++) { - minX = Math.min(minX, coords[i].column); - minY = Math.min(minY, coords[i].row); - maxX = Math.max(maxX, coords[i].column); - maxY = Math.max(maxY, coords[i].row); + var loading = this.loading[fontstack]; + if (loading[range]) { + loading[range].push(callback); + } else { + loading[range] = [callback]; + var rangeName = range * 256 + '-' + (range * 256 + 255); + var url = glyphUrl(fontstack, rangeName, this.url); + ajax.getArrayBuffer(url, function (err, data) { + var glyphs = !err && new Glyphs(new Protobuf(data)); + for (var i = 0; i < loading[range].length; i++) { + loading[range][i](err, range, glyphs); + } + delete loading[range]; + }); } - - var dx = maxX - minX; - var dy = maxY - minY; - var dMax = Math.max(dx, dy); - return new Coordinate((minX + maxX) / 2, (minY + maxY) / 2, 0) - .zoomTo(Math.floor(-Math.log(dMax) / Math.LN2)); }; - -/** - * Determine if a string ends with a particular substring - * @param {string} string - * @param {string} suffix - * @returns {boolean} - * @private - */ -exports.endsWith = function(string, suffix) { - return string.indexOf(suffix, string.length - suffix.length) !== -1; +GlyphSource.prototype.getGlyphAtlas = function (fontstack) { + return this.atlases[fontstack]; }; - -/** - * Determine if a string starts with a particular substring - * @param {string} string - * @param {string} prefix - * @returns {boolean} - * @private - */ -exports.startsWith = function(string, prefix) { - return string.indexOf(prefix) === 0; -}; - -/** - * Create an object by mapping all the values of an existing object while - * preserving their keys. - * @param {Object} input - * @param {Function} iterator - * @returns {Object} - * @private - */ -exports.mapObject = function(input, iterator, context) { - var output = {}; - for (var key in input) { - output[key] = iterator.call(context || this, input[key], key, input); +function glyphUrl(fontstack, range, url, subdomains) { + subdomains = subdomains || 'abc'; + return url.replace('{s}', subdomains[fontstack.length % subdomains.length]).replace('{fontstack}', fontstack).replace('{range}', range); +} +},{"../symbol/glyph_atlas":142,"../util/ajax":170,"../util/glyphs":181,"../util/mapbox":185,"pbf":192}],144:[function(require,module,exports){ +'use strict'; +module.exports = function (features, textFeatures, geometries) { + var leftIndex = {}, rightIndex = {}, mergedFeatures = [], mergedGeom = [], mergedTexts = [], mergedIndex = 0, k; + function add(k) { + mergedFeatures.push(features[k]); + mergedGeom.push(geometries[k]); + mergedTexts.push(textFeatures[k]); + mergedIndex++; } - return output; -}; - -/** - * Create an object by filtering out values of an existing object - * @param {Object} input - * @param {Function} iterator - * @returns {Object} - * @private - */ -exports.filterObject = function(input, iterator, context) { - var output = {}; - for (var key in input) { - if (iterator.call(context || this, input[key], key, input)) { - output[key] = input[key]; + function mergeFromRight(leftKey, rightKey, geom) { + var i = rightIndex[leftKey]; + delete rightIndex[leftKey]; + rightIndex[rightKey] = i; + mergedGeom[i][0].pop(); + mergedGeom[i][0] = mergedGeom[i][0].concat(geom[0]); + return i; + } + function mergeFromLeft(leftKey, rightKey, geom) { + var i = leftIndex[rightKey]; + delete leftIndex[rightKey]; + leftIndex[leftKey] = i; + mergedGeom[i][0].shift(); + mergedGeom[i][0] = geom[0].concat(mergedGeom[i][0]); + return i; + } + function getKey(text, geom, onRight) { + var point = onRight ? geom[0][geom[0].length - 1] : geom[0][0]; + return text + ':' + point.x + ':' + point.y; + } + for (k = 0; k < features.length; k++) { + var geom = geometries[k], text = textFeatures[k]; + if (!text) { + add(k); + continue; + } + var leftKey = getKey(text, geom), rightKey = getKey(text, geom, true); + if (leftKey in rightIndex && rightKey in leftIndex && rightIndex[leftKey] !== leftIndex[rightKey]) { + var j = mergeFromLeft(leftKey, rightKey, geom); + var i = mergeFromRight(leftKey, rightKey, mergedGeom[j]); + delete leftIndex[leftKey]; + delete rightIndex[rightKey]; + rightIndex[getKey(text, mergedGeom[i], true)] = i; + mergedGeom[j] = null; + } else if (leftKey in rightIndex) { + mergeFromRight(leftKey, rightKey, geom); + } else if (rightKey in leftIndex) { + mergeFromLeft(leftKey, rightKey, geom); + } else { + add(k); + leftIndex[leftKey] = mergedIndex - 1; + rightIndex[rightKey] = mergedIndex - 1; } } - return output; + return { + features: mergedFeatures, + textFeatures: mergedTexts, + geometries: mergedGeom + }; }; - -},{"../geo/coordinate":25,"unitbezier":167}],114:[function(require,module,exports){ -// (c) Dean McNamee , 2012. -// -// https://github.com/deanm/css-color-parser-js -// -// 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. - -// http://www.w3.org/TR/css3-color/ -var kCSSColorTable = { - "transparent": [0,0,0,0], "aliceblue": [240,248,255,1], - "antiquewhite": [250,235,215,1], "aqua": [0,255,255,1], - "aquamarine": [127,255,212,1], "azure": [240,255,255,1], - "beige": [245,245,220,1], "bisque": [255,228,196,1], - "black": [0,0,0,1], "blanchedalmond": [255,235,205,1], - "blue": [0,0,255,1], "blueviolet": [138,43,226,1], - "brown": [165,42,42,1], "burlywood": [222,184,135,1], - "cadetblue": [95,158,160,1], "chartreuse": [127,255,0,1], - "chocolate": [210,105,30,1], "coral": [255,127,80,1], - "cornflowerblue": [100,149,237,1], "cornsilk": [255,248,220,1], - "crimson": [220,20,60,1], "cyan": [0,255,255,1], - "darkblue": [0,0,139,1], "darkcyan": [0,139,139,1], - "darkgoldenrod": [184,134,11,1], "darkgray": [169,169,169,1], - "darkgreen": [0,100,0,1], "darkgrey": [169,169,169,1], - "darkkhaki": [189,183,107,1], "darkmagenta": [139,0,139,1], - "darkolivegreen": [85,107,47,1], "darkorange": [255,140,0,1], - "darkorchid": [153,50,204,1], "darkred": [139,0,0,1], - "darksalmon": [233,150,122,1], "darkseagreen": [143,188,143,1], - "darkslateblue": [72,61,139,1], "darkslategray": [47,79,79,1], - "darkslategrey": [47,79,79,1], "darkturquoise": [0,206,209,1], - "darkviolet": [148,0,211,1], "deeppink": [255,20,147,1], - "deepskyblue": [0,191,255,1], "dimgray": [105,105,105,1], - "dimgrey": [105,105,105,1], "dodgerblue": [30,144,255,1], - "firebrick": [178,34,34,1], "floralwhite": [255,250,240,1], - "forestgreen": [34,139,34,1], "fuchsia": [255,0,255,1], - "gainsboro": [220,220,220,1], "ghostwhite": [248,248,255,1], - "gold": [255,215,0,1], "goldenrod": [218,165,32,1], - "gray": [128,128,128,1], "green": [0,128,0,1], - "greenyellow": [173,255,47,1], "grey": [128,128,128,1], - "honeydew": [240,255,240,1], "hotpink": [255,105,180,1], - "indianred": [205,92,92,1], "indigo": [75,0,130,1], - "ivory": [255,255,240,1], "khaki": [240,230,140,1], - "lavender": [230,230,250,1], "lavenderblush": [255,240,245,1], - "lawngreen": [124,252,0,1], "lemonchiffon": [255,250,205,1], - "lightblue": [173,216,230,1], "lightcoral": [240,128,128,1], - "lightcyan": [224,255,255,1], "lightgoldenrodyellow": [250,250,210,1], - "lightgray": [211,211,211,1], "lightgreen": [144,238,144,1], - "lightgrey": [211,211,211,1], "lightpink": [255,182,193,1], - "lightsalmon": [255,160,122,1], "lightseagreen": [32,178,170,1], - "lightskyblue": [135,206,250,1], "lightslategray": [119,136,153,1], - "lightslategrey": [119,136,153,1], "lightsteelblue": [176,196,222,1], - "lightyellow": [255,255,224,1], "lime": [0,255,0,1], - "limegreen": [50,205,50,1], "linen": [250,240,230,1], - "magenta": [255,0,255,1], "maroon": [128,0,0,1], - "mediumaquamarine": [102,205,170,1], "mediumblue": [0,0,205,1], - "mediumorchid": [186,85,211,1], "mediumpurple": [147,112,219,1], - "mediumseagreen": [60,179,113,1], "mediumslateblue": [123,104,238,1], - "mediumspringgreen": [0,250,154,1], "mediumturquoise": [72,209,204,1], - "mediumvioletred": [199,21,133,1], "midnightblue": [25,25,112,1], - "mintcream": [245,255,250,1], "mistyrose": [255,228,225,1], - "moccasin": [255,228,181,1], "navajowhite": [255,222,173,1], - "navy": [0,0,128,1], "oldlace": [253,245,230,1], - "olive": [128,128,0,1], "olivedrab": [107,142,35,1], - "orange": [255,165,0,1], "orangered": [255,69,0,1], - "orchid": [218,112,214,1], "palegoldenrod": [238,232,170,1], - "palegreen": [152,251,152,1], "paleturquoise": [175,238,238,1], - "palevioletred": [219,112,147,1], "papayawhip": [255,239,213,1], - "peachpuff": [255,218,185,1], "peru": [205,133,63,1], - "pink": [255,192,203,1], "plum": [221,160,221,1], - "powderblue": [176,224,230,1], "purple": [128,0,128,1], - "red": [255,0,0,1], "rosybrown": [188,143,143,1], - "royalblue": [65,105,225,1], "saddlebrown": [139,69,19,1], - "salmon": [250,128,114,1], "sandybrown": [244,164,96,1], - "seagreen": [46,139,87,1], "seashell": [255,245,238,1], - "sienna": [160,82,45,1], "silver": [192,192,192,1], - "skyblue": [135,206,235,1], "slateblue": [106,90,205,1], - "slategray": [112,128,144,1], "slategrey": [112,128,144,1], - "snow": [255,250,250,1], "springgreen": [0,255,127,1], - "steelblue": [70,130,180,1], "tan": [210,180,140,1], - "teal": [0,128,128,1], "thistle": [216,191,216,1], - "tomato": [255,99,71,1], "turquoise": [64,224,208,1], - "violet": [238,130,238,1], "wheat": [245,222,179,1], - "white": [255,255,255,1], "whitesmoke": [245,245,245,1], - "yellow": [255,255,0,1], "yellowgreen": [154,205,50,1]} - -function clamp_css_byte(i) { // Clamp to integer 0 .. 255. - i = Math.round(i); // Seems to be what Chrome does (vs truncation). - return i < 0 ? 0 : i > 255 ? 255 : i; +},{}],145:[function(require,module,exports){ +'use strict'; +var Point = require('point-geometry'); +module.exports = { + getIconQuads: getIconQuads, + getGlyphQuads: getGlyphQuads, + SymbolQuad: SymbolQuad +}; +var minScale = 0.5; +function SymbolQuad(anchorPoint, tl, tr, bl, br, tex, anchorAngle, glyphAngle, minScale, maxScale) { + this.anchorPoint = anchorPoint; + this.tl = tl; + this.tr = tr; + this.bl = bl; + this.br = br; + this.tex = tex; + this.anchorAngle = anchorAngle; + this.glyphAngle = glyphAngle; + this.minScale = minScale; + this.maxScale = maxScale; } - -function clamp_css_float(f) { // Clamp to float 0.0 .. 1.0. - return f < 0 ? 0 : f > 1 ? 1 : f; +function getIconQuads(anchor, shapedIcon, boxScale, line, layer, alongLine, shapedText, globalProperties, featureProperties) { + var rect = shapedIcon.image.rect; + var layout = layer.layout; + var border = 1; + var left = shapedIcon.left - border; + var right = left + rect.w / shapedIcon.image.pixelRatio; + var top = shapedIcon.top - border; + var bottom = top + rect.h / shapedIcon.image.pixelRatio; + var tl, tr, br, bl; + if (layout['icon-text-fit'] !== 'none' && shapedText) { + var iconWidth = right - left, iconHeight = bottom - top, size = layout['text-size'] / 24, textLeft = shapedText.left * size, textRight = shapedText.right * size, textTop = shapedText.top * size, textBottom = shapedText.bottom * size, textWidth = textRight - textLeft, textHeight = textBottom - textTop, padT = layout['icon-text-fit-padding'][0], padR = layout['icon-text-fit-padding'][1], padB = layout['icon-text-fit-padding'][2], padL = layout['icon-text-fit-padding'][3], offsetY = layout['icon-text-fit'] === 'width' ? (textHeight - iconHeight) * 0.5 : 0, offsetX = layout['icon-text-fit'] === 'height' ? (textWidth - iconWidth) * 0.5 : 0, width = layout['icon-text-fit'] === 'width' || layout['icon-text-fit'] === 'both' ? textWidth : iconWidth, height = layout['icon-text-fit'] === 'height' || layout['icon-text-fit'] === 'both' ? textHeight : iconHeight; + tl = new Point(textLeft + offsetX - padL, textTop + offsetY - padT); + tr = new Point(textLeft + offsetX + padR + width, textTop + offsetY - padT); + br = new Point(textLeft + offsetX + padR + width, textTop + offsetY + padB + height); + bl = new Point(textLeft + offsetX - padL, textTop + offsetY + padB + height); + } else { + tl = new Point(left, top); + tr = new Point(right, top); + br = new Point(right, bottom); + bl = new Point(left, bottom); + } + var angle = layer.getLayoutValue('icon-rotate', globalProperties, featureProperties) * Math.PI / 180; + if (alongLine) { + var prev = line[anchor.segment]; + if (anchor.y === prev.y && anchor.x === prev.x && anchor.segment + 1 < line.length) { + var next = line[anchor.segment + 1]; + angle += Math.atan2(anchor.y - next.y, anchor.x - next.x) + Math.PI; + } else { + angle += Math.atan2(anchor.y - prev.y, anchor.x - prev.x); + } + } + if (angle) { + var sin = Math.sin(angle), cos = Math.cos(angle), matrix = [ + cos, + -sin, + sin, + cos + ]; + tl = tl.matMult(matrix); + tr = tr.matMult(matrix); + bl = bl.matMult(matrix); + br = br.matMult(matrix); + } + return [new SymbolQuad(new Point(anchor.x, anchor.y), tl, tr, bl, br, shapedIcon.image.rect, 0, 0, minScale, Infinity)]; } - -function parse_css_int(str) { // int or percentage. - if (str[str.length - 1] === '%') - return clamp_css_byte(parseFloat(str) / 100 * 255); - return clamp_css_byte(parseInt(str)); +function getGlyphQuads(anchor, shaping, boxScale, line, layer, alongLine) { + var textRotate = layer.layout['text-rotate'] * Math.PI / 180; + var keepUpright = layer.layout['text-keep-upright']; + var positionedGlyphs = shaping.positionedGlyphs; + var quads = []; + for (var k = 0; k < positionedGlyphs.length; k++) { + var positionedGlyph = positionedGlyphs[k]; + var glyph = positionedGlyph.glyph; + if (!glyph) + continue; + var rect = glyph.rect; + if (!rect) + continue; + var centerX = (positionedGlyph.x + glyph.advance / 2) * boxScale; + var glyphInstances; + var labelMinScale = minScale; + if (alongLine) { + glyphInstances = []; + labelMinScale = getSegmentGlyphs(glyphInstances, anchor, centerX, line, anchor.segment, true); + if (keepUpright) { + labelMinScale = Math.min(labelMinScale, getSegmentGlyphs(glyphInstances, anchor, centerX, line, anchor.segment, false)); + } + } else { + glyphInstances = [{ + anchorPoint: new Point(anchor.x, anchor.y), + offset: 0, + angle: 0, + maxScale: Infinity, + minScale: minScale + }]; + } + var x1 = positionedGlyph.x + glyph.left, y1 = positionedGlyph.y - glyph.top, x2 = x1 + rect.w, y2 = y1 + rect.h, otl = new Point(x1, y1), otr = new Point(x2, y1), obl = new Point(x1, y2), obr = new Point(x2, y2); + for (var i = 0; i < glyphInstances.length; i++) { + var instance = glyphInstances[i], tl = otl, tr = otr, bl = obl, br = obr; + if (textRotate) { + var sin = Math.sin(textRotate), cos = Math.cos(textRotate), matrix = [ + cos, + -sin, + sin, + cos + ]; + tl = tl.matMult(matrix); + tr = tr.matMult(matrix); + bl = bl.matMult(matrix); + br = br.matMult(matrix); + } + var glyphMinScale = Math.max(instance.minScale, labelMinScale); + var anchorAngle = (anchor.angle + instance.offset + 2 * Math.PI) % (2 * Math.PI); + var glyphAngle = (instance.angle + instance.offset + 2 * Math.PI) % (2 * Math.PI); + quads.push(new SymbolQuad(instance.anchorPoint, tl, tr, bl, br, rect, anchorAngle, glyphAngle, glyphMinScale, instance.maxScale)); + } + } + return quads; } - -function parse_css_float(str) { // float or percentage. - if (str[str.length - 1] === '%') - return clamp_css_float(parseFloat(str) / 100); - return clamp_css_float(parseFloat(str)); -} - -function css_hue_to_rgb(m1, m2, h) { - if (h < 0) h += 1; - else if (h > 1) h -= 1; - - if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; - if (h * 2 < 1) return m2; - if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; - return m1; -} - -function parseCSSColor(css_str) { - // Remove all whitespace, not compliant, but should just be more accepting. - var str = css_str.replace(/ /g, '').toLowerCase(); - - // Color keywords (and transparent) lookup. - if (str in kCSSColorTable) return kCSSColorTable[str].slice(); // dup. - - // #abc and #abc123 syntax. - if (str[0] === '#') { - if (str.length === 4) { - var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. - if (!(iv >= 0 && iv <= 0xfff)) return null; // Covers NaN. - return [((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8), - (iv & 0xf0) | ((iv & 0xf0) >> 4), - (iv & 0xf) | ((iv & 0xf) << 4), - 1]; - } else if (str.length === 7) { - var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. - if (!(iv >= 0 && iv <= 0xffffff)) return null; // Covers NaN. - return [(iv & 0xff0000) >> 16, - (iv & 0xff00) >> 8, - iv & 0xff, - 1]; - } - - return null; - } - - var op = str.indexOf('('), ep = str.indexOf(')'); - if (op !== -1 && ep + 1 === str.length) { - var fname = str.substr(0, op); - var params = str.substr(op+1, ep-(op+1)).split(','); - var alpha = 1; // To allow case fallthrough. - switch (fname) { - case 'rgba': - if (params.length !== 4) return null; - alpha = parse_css_float(params.pop()); - // Fall through. - case 'rgb': - if (params.length !== 3) return null; - return [parse_css_int(params[0]), - parse_css_int(params[1]), - parse_css_int(params[2]), - alpha]; - case 'hsla': - if (params.length !== 4) return null; - alpha = parse_css_float(params.pop()); - // Fall through. - case 'hsl': - if (params.length !== 3) return null; - var h = (((parseFloat(params[0]) % 360) + 360) % 360) / 360; // 0 .. 1 - // NOTE(deanm): According to the CSS spec s/l should only be - // percentages, but we don't bother and let float or percentage. - var s = parse_css_float(params[1]); - var l = parse_css_float(params[2]); - var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; - var m1 = l * 2 - m2; - return [clamp_css_byte(css_hue_to_rgb(m1, m2, h+1/3) * 255), - clamp_css_byte(css_hue_to_rgb(m1, m2, h) * 255), - clamp_css_byte(css_hue_to_rgb(m1, m2, h-1/3) * 255), - alpha]; - default: - return null; +function getSegmentGlyphs(glyphs, anchor, offset, line, segment, forward) { + var upsideDown = !forward; + if (offset < 0) + forward = !forward; + if (forward) + segment++; + var newAnchorPoint = new Point(anchor.x, anchor.y); + var end = line[segment]; + var prevScale = Infinity; + offset = Math.abs(offset); + var placementScale = minScale; + while (true) { + var distance = newAnchorPoint.dist(end); + var scale = offset / distance; + var angle = Math.atan2(end.y - newAnchorPoint.y, end.x - newAnchorPoint.x); + if (!forward) + angle += Math.PI; + glyphs.push({ + anchorPoint: newAnchorPoint, + offset: upsideDown ? Math.PI : 0, + minScale: scale, + maxScale: prevScale, + angle: (angle + 2 * Math.PI) % (2 * Math.PI) + }); + if (scale <= placementScale) + break; + newAnchorPoint = end; + while (newAnchorPoint.equals(end)) { + segment += forward ? 1 : -1; + end = line[segment]; + if (!end) { + return scale; + } + } + var unit = end.sub(newAnchorPoint)._unit(); + newAnchorPoint = newAnchorPoint.sub(unit._mult(distance)); + prevScale = scale; } - } - - return null; + return placementScale; } - -try { exports.parseCSSColor = parseCSSColor } catch(e) { } - -},{}],115:[function(require,module,exports){ +},{"point-geometry":196}],146:[function(require,module,exports){ 'use strict'; - -module.exports = createFilter; - -var types = ['Unknown', 'Point', 'LineString', 'Polygon']; - -/** - * Given a filter expressed as nested arrays, return a new function - * that evaluates whether a given feature (with a .properties or .tags property) - * passes its test. - * - * @param {Array} filter mapbox gl filter - * @returns {Function} filter-evaluating function - */ -function createFilter(filter) { - return new Function('f', 'return ' + compile(filter)); -} - -function compile(filter) { - if (!filter) return 'true'; - var op = filter[0]; - if (filter.length <= 1) return op === 'any' ? 'false' : 'true'; - var str = - op === '==' ? compare(filter[1], filter[2], '===', false) : - op === '!=' ? compare(filter[1], filter[2], '!==', false) : - op === '<' || - op === '>' || - op === '<=' || - op === '>=' ? compare(filter[1], filter[2], op, true) : - op === 'any' ? filter.slice(1).map(compile).join('||') : - op === 'all' ? filter.slice(1).map(compile).join('&&') : - op === 'none' ? '!(' + filter.slice(1).map(compile).join('||') + ')' : - op === 'in' ? compileIn(filter[1], filter.slice(2)) : - op === '!in' ? '!(' + compileIn(filter[1], filter.slice(2)) + ')' : - 'true'; - return '(' + str + ')'; -} - -function valueExpr(key) { - return key === '$type' ? 'f.type' : '(f.properties || {})[' + JSON.stringify(key) + ']'; -} -function compare(key, val, op, checkType) { - var left = valueExpr(key); - var right = key === '$type' ? types.indexOf(val) : JSON.stringify(val); - return (checkType ? 'typeof ' + left + '=== typeof ' + right + '&&' : '') + left + op + right; +var resolveTokens = require('../util/token'); +module.exports = resolveText; +function resolveText(features, layoutProperties, codepoints) { + var textFeatures = []; + for (var i = 0, fl = features.length; i < fl; i++) { + var text = resolveTokens(features[i].properties, layoutProperties['text-field']); + if (!text) { + textFeatures[i] = null; + continue; + } + text = text.toString(); + var transform = layoutProperties['text-transform']; + if (transform === 'uppercase') { + text = text.toLocaleUpperCase(); + } else if (transform === 'lowercase') { + text = text.toLocaleLowerCase(); + } + for (var j = 0; j < text.length; j++) { + codepoints[text.charCodeAt(j)] = true; + } + textFeatures[i] = text; + } + return textFeatures; } -function compileIn(key, values) { - if (key === '$type') values = values.map(types.indexOf.bind(types)); - var left = JSON.stringify(values.sort(compareFn)); - var right = valueExpr(key); - - if (values.length <= 200) return left + '.indexOf(' + right + ') !== -1'; - - return 'function(v, a, i, j) {' + - 'while (i <= j) { var m = (i + j) >> 1;' + - ' if (a[m] === v) return true; if (a[m] > v) j = m - 1; else i = m + 1;' + - '}' + - 'return false; }(' + right + ', ' + left + ',0,' + (values.length - 1) + ')'; +},{"../util/token":187}],147:[function(require,module,exports){ +'use strict'; +module.exports = { + shapeText: shapeText, + shapeIcon: shapeIcon +}; +function PositionedGlyph(codePoint, x, y, glyph) { + this.codePoint = codePoint; + this.x = x; + this.y = y; + this.glyph = glyph || null; } - -function compareFn(a, b) { - return a < b ? -1 : a > b ? 1 : 0; +function Shaping(positionedGlyphs, text, top, bottom, left, right) { + this.positionedGlyphs = positionedGlyphs; + this.text = text; + this.top = top; + this.bottom = bottom; + this.left = left; + this.right = right; } - -},{}],116:[function(require,module,exports){ -'use strict'; - -module.exports = clip; - -/* clip features between two axis-parallel lines: - * | | - * ___|___ | / - * / | \____|____/ - * | | - */ - -function clip(features, scale, k1, k2, axis, intersect, minAll, maxAll) { - - k1 /= scale; - k2 /= scale; - - if (minAll >= k1 && maxAll <= k2) return features; // trivial accept - else if (minAll > k2 || maxAll < k1) return null; // trivial reject - - var clipped = []; - - for (var i = 0; i < features.length; i++) { - - var feature = features[i], - geometry = feature.geometry, - type = feature.type, - min, max; - - min = feature.min[axis]; - max = feature.max[axis]; - - if (min >= k1 && max <= k2) { // trivial accept - clipped.push(feature); +var newLine = 10; +function shapeText(text, glyphs, maxWidth, lineHeight, horizontalAlign, verticalAlign, justify, spacing, translate) { + var positionedGlyphs = []; + var shaping = new Shaping(positionedGlyphs, text, translate[1], translate[1], translate[0], translate[0]); + var yOffset = -17; + var x = 0; + var y = yOffset; + text = text.trim(); + for (var i = 0; i < text.length; i++) { + var codePoint = text.charCodeAt(i); + var glyph = glyphs[codePoint]; + if (!glyph && codePoint !== newLine) continue; - } else if (min > k2 || max < k1) continue; // trivial reject - - var slices = type === 1 ? - clipPoints(geometry, k1, k2, axis) : - clipGeometry(geometry, k1, k2, axis, intersect, type === 3); - - if (slices.length) { - // if a feature got clipped, it will likely get clipped on the next zoom level as well, - // so there's no need to recalculate bboxes - clipped.push({ - geometry: slices, - type: type, - tags: features[i].tags || null, - min: feature.min, - max: feature.max - }); + positionedGlyphs.push(new PositionedGlyph(codePoint, x, y, glyph)); + if (glyph) { + x += glyph.advance + spacing; } } - - return clipped.length ? clipped : null; + if (!positionedGlyphs.length) + return false; + linewrap(shaping, glyphs, lineHeight, maxWidth, horizontalAlign, verticalAlign, justify, translate); + return shaping; } - -function clipPoints(geometry, k1, k2, axis) { - var slice = []; - - for (var i = 0; i < geometry.length; i++) { - var a = geometry[i], - ak = a[axis]; - - if (ak >= k1 && ak <= k2) slice.push(a); - } - return slice; -} - -function clipGeometry(geometry, k1, k2, axis, intersect, closed) { - - var slices = []; - - for (var i = 0; i < geometry.length; i++) { - - var ak = 0, - bk = 0, - b = null, - points = geometry[i], - area = points.area, - dist = points.dist, - len = points.length, - a, j, last; - - var slice = []; - - for (j = 0; j < len - 1; j++) { - a = b || points[j]; - b = points[j + 1]; - ak = bk || a[axis]; - bk = b[axis]; - - if (ak < k1) { - - if ((bk > k2)) { // ---|-----|--> - slice.push(intersect(a, b, k1), intersect(a, b, k2)); - if (!closed) slice = newSlice(slices, slice, area, dist); - - } else if (bk >= k1) slice.push(intersect(a, b, k1)); // ---|--> | - - } else if (ak > k2) { - - if ((bk < k1)) { // <--|-----|--- - slice.push(intersect(a, b, k2), intersect(a, b, k1)); - if (!closed) slice = newSlice(slices, slice, area, dist); - - } else if (bk <= k2) slice.push(intersect(a, b, k2)); // | <--|--- - - } else { - - slice.push(a); - - if (bk < k1) { // <--|--- | - slice.push(intersect(a, b, k1)); - if (!closed) slice = newSlice(slices, slice, area, dist); - - } else if (bk > k2) { // | ---|--> - slice.push(intersect(a, b, k2)); - if (!closed) slice = newSlice(slices, slice, area, dist); +var invisible = { + 32: true, + 8203: true +}; +var breakable = { + 32: true, + 38: true, + 43: true, + 45: true, + 47: true, + 173: true, + 183: true, + 8203: true, + 8208: true, + 8211: true +}; +invisible[newLine] = breakable[newLine] = true; +function linewrap(shaping, glyphs, lineHeight, maxWidth, horizontalAlign, verticalAlign, justify, translate) { + var lastSafeBreak = null; + var lengthBeforeCurrentLine = 0; + var lineStartIndex = 0; + var line = 0; + var maxLineLength = 0; + var positionedGlyphs = shaping.positionedGlyphs; + if (maxWidth) { + for (var i = 0; i < positionedGlyphs.length; i++) { + var positionedGlyph = positionedGlyphs[i]; + positionedGlyph.x -= lengthBeforeCurrentLine; + positionedGlyph.y += lineHeight * line; + if (lastSafeBreak !== null && (positionedGlyph.x > maxWidth || positionedGlyphs[lastSafeBreak].codePoint === newLine)) { + var lineLength = positionedGlyphs[lastSafeBreak + 1].x; + maxLineLength = Math.max(lineLength, maxLineLength); + for (var k = lastSafeBreak + 1; k <= i; k++) { + positionedGlyphs[k].y += lineHeight; + positionedGlyphs[k].x -= lineLength; } - // | --> | + if (justify) { + var lineEnd = lastSafeBreak; + if (invisible[positionedGlyphs[lastSafeBreak].codePoint]) { + lineEnd--; + } + justifyLine(positionedGlyphs, glyphs, lineStartIndex, lineEnd, justify); + } + lineStartIndex = lastSafeBreak + 1; + lastSafeBreak = null; + lengthBeforeCurrentLine += lineLength; + line++; + } + if (breakable[positionedGlyph.codePoint]) { + lastSafeBreak = i; } } - - // add the last point - a = points[len - 1]; - ak = a[axis]; - if (ak >= k1 && ak <= k2) slice.push(a); - - // close the polygon if its endpoints are not the same after clipping - - last = slice[slice.length - 1]; - if (closed && last && (slice[0][0] !== last[0] || slice[0][1] !== last[1])) slice.push(slice[0]); - - // add the final slice - newSlice(slices, slice, area, dist); } - - return slices; + var lastPositionedGlyph = positionedGlyphs[positionedGlyphs.length - 1]; + var lastLineLength = lastPositionedGlyph.x + glyphs[lastPositionedGlyph.codePoint].advance; + maxLineLength = Math.max(maxLineLength, lastLineLength); + var height = (line + 1) * lineHeight; + justifyLine(positionedGlyphs, glyphs, lineStartIndex, positionedGlyphs.length - 1, justify); + align(positionedGlyphs, justify, horizontalAlign, verticalAlign, maxLineLength, lineHeight, line, translate); + shaping.top += -verticalAlign * height; + shaping.bottom = shaping.top + height; + shaping.left += -horizontalAlign * maxLineLength; + shaping.right = shaping.left + maxLineLength; } - -function newSlice(slices, slice, area, dist) { - if (slice.length) { - // we don't recalculate the area/length of the unclipped geometry because the case where it goes - // below the visibility threshold as a result of clipping is rare, so we avoid doing unnecessary work - slice.area = area; - slice.dist = dist; - - slices.push(slice); +function justifyLine(positionedGlyphs, glyphs, start, end, justify) { + var lastAdvance = glyphs[positionedGlyphs[end].codePoint].advance; + var lineIndent = (positionedGlyphs[end].x + lastAdvance) * justify; + for (var j = start; j <= end; j++) { + positionedGlyphs[j].x -= lineIndent; } - return []; } - -},{}],117:[function(require,module,exports){ -'use strict'; - -module.exports = convert; - -var simplify = require('./simplify'); - -// converts GeoJSON feature into an intermediate projected JSON vector format with simplification data - -function convert(data, tolerance) { - var features = []; - - if (data.type === 'FeatureCollection') { - for (var i = 0; i < data.features.length; i++) { - convertFeature(features, data.features[i], tolerance); - } - } else if (data.type === 'Feature') { - convertFeature(features, data, tolerance); - - } else { - // single geometry or a geometry collection - convertFeature(features, {geometry: data}, tolerance); +function align(positionedGlyphs, justify, horizontalAlign, verticalAlign, maxLineLength, lineHeight, line, translate) { + var shiftX = (justify - horizontalAlign) * maxLineLength + translate[0]; + var shiftY = (-verticalAlign * (line + 1) + 0.5) * lineHeight + translate[1]; + for (var j = 0; j < positionedGlyphs.length; j++) { + positionedGlyphs[j].x += shiftX; + positionedGlyphs[j].y += shiftY; } - return features; } - -function convertFeature(features, feature, tolerance) { - var geom = feature.geometry, - type = geom.type, - coords = geom.coordinates, - tags = feature.properties, - i, j, rings; - - if (type === 'Point') { - features.push(create(tags, 1, [projectPoint(coords)])); - - } else if (type === 'MultiPoint') { - features.push(create(tags, 1, project(coords))); - - } else if (type === 'LineString') { - features.push(create(tags, 2, [project(coords, tolerance)])); - - } else if (type === 'MultiLineString' || type === 'Polygon') { - rings = []; - for (i = 0; i < coords.length; i++) { - rings.push(project(coords[i], tolerance)); - } - features.push(create(tags, type === 'Polygon' ? 3 : 2, rings)); - - } else if (type === 'MultiPolygon') { - rings = []; - for (i = 0; i < coords.length; i++) { - for (j = 0; j < coords[i].length; j++) { - rings.push(project(coords[i][j], tolerance)); +function shapeIcon(image, layout) { + if (!image || !image.rect) + return null; + var dx = layout['icon-offset'][0]; + var dy = layout['icon-offset'][1]; + var x1 = dx - image.width / 2; + var x2 = x1 + image.width; + var y1 = dy - image.height / 2; + var y2 = y1 + image.height; + return new PositionedIcon(image, y1, y2, x1, x2); +} +function PositionedIcon(image, top, bottom, left, right) { + this.image = image; + this.top = top; + this.bottom = bottom; + this.left = left; + this.right = right; +} +},{}],148:[function(require,module,exports){ +'use strict'; +var ShelfPack = require('shelf-pack'); +var browser = require('../util/browser'); +var util = require('../util/util'); +module.exports = SpriteAtlas; +function SpriteAtlas(width, height) { + this.width = width; + this.height = height; + this.bin = new ShelfPack(width, height); + this.images = {}; + this.data = false; + this.texture = 0; + this.filter = 0; + this.pixelRatio = 1; + this.dirty = true; +} +function copyBitmap(src, srcStride, srcX, srcY, dst, dstStride, dstX, dstY, width, height, wrap) { + var srcI = srcY * srcStride + srcX; + var dstI = dstY * dstStride + dstX; + var x, y; + if (wrap) { + dstI -= dstStride; + for (y = -1; y <= height; y++, srcI = ((y + height) % height + srcY) * srcStride + srcX, dstI += dstStride) { + for (x = -1; x <= width; x++) { + dst[dstI + x] = src[srcI + (x + width) % width]; } } - features.push(create(tags, 3, rings)); - - } else if (type === 'GeometryCollection') { - for (i = 0; i < geom.geometries.length; i++) { - convertFeature(features, { - geometry: geom.geometries[i], - properties: tags - }, tolerance); - } - } else { - throw new Error('Input data is not a valid GeoJSON object.'); + for (y = 0; y < height; y++, srcI += srcStride, dstI += dstStride) { + for (x = 0; x < width; x++) { + dst[dstI + x] = src[srcI + x]; + } + } } } - -function create(tags, type, geometry) { - var feature = { - geometry: geometry, - type: type, - tags: tags || null, - min: [2, 1], // initial bbox values; - max: [-1, 0] // note that coords are usually in [0..1] range - }; - calcBBox(feature); - return feature; -} - -function project(lonlats, tolerance) { - var projected = []; - for (var i = 0; i < lonlats.length; i++) { - projected.push(projectPoint(lonlats[i])); - } - if (tolerance) { - simplify(projected, tolerance); - calcSize(projected); +SpriteAtlas.prototype.allocateImage = function (pixelWidth, pixelHeight) { + pixelWidth = pixelWidth / this.pixelRatio; + pixelHeight = pixelHeight / this.pixelRatio; + var padding = 2; + var packWidth = pixelWidth + padding + (4 - (pixelWidth + padding) % 4); + var packHeight = pixelHeight + padding + (4 - (pixelHeight + padding) % 4); + var rect = this.bin.packOne(packWidth, packHeight); + if (!rect) { + util.warnOnce('SpriteAtlas out of space.'); + return null; } - return projected; -} - -function projectPoint(p) { - var sin = Math.sin(p[1] * Math.PI / 180), - x = (p[0] / 360 + 0.5), - y = (0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI); - - y = y < -1 ? -1 : - y > 1 ? 1 : y; - - return [x, y, 0]; -} - -// calculate area and length of the poly -function calcSize(points) { - var area = 0, - dist = 0; - - for (var i = 0, a, b; i < points.length - 1; i++) { - a = b || points[i]; - b = points[i + 1]; - - area += a[0] * b[1] - b[0] * a[1]; - - // use Manhattan distance instead of Euclidian one to avoid expensive square root computation - dist += Math.abs(b[0] - a[0]) + Math.abs(b[1] - a[1]); + return rect; +}; +SpriteAtlas.prototype.getImage = function (name, wrap) { + if (this.images[name]) { + return this.images[name]; } - points.area = Math.abs(area / 2); - points.dist = dist; -} - -// calculate the feature bounding box for faster clipping later -function calcBBox(feature) { - var geometry = feature.geometry, - min = feature.min, - max = feature.max; - - if (feature.type === 1) calcRingBBox(min, max, geometry); - else for (var i = 0; i < geometry.length; i++) calcRingBBox(min, max, geometry[i]); - - return feature; -} - -function calcRingBBox(min, max, points) { - for (var i = 0, p; i < points.length; i++) { - p = points[i]; - min[0] = Math.min(p[0], min[0]); - max[0] = Math.max(p[0], max[0]); - min[1] = Math.min(p[1], min[1]); - max[1] = Math.max(p[1], max[1]); + if (!this.sprite) { + return null; } -} - -},{"./simplify":119}],118:[function(require,module,exports){ -'use strict'; - -module.exports = geojsonvt; - -var convert = require('./convert'), // GeoJSON conversion and preprocessing - transform = require('./transform'), // coordinate transformation - clip = require('./clip'), // stripe clipping algorithm - wrap = require('./wrap'), // date line processing - createTile = require('./tile'); // final simplified tile generation - - -function geojsonvt(data, options) { - return new GeoJSONVT(data, options); -} - -function GeoJSONVT(data, options) { - options = this.options = extend(Object.create(this.options), options); - - var debug = options.debug; - - if (debug) console.time('preprocess data'); - - var z2 = 1 << options.maxZoom, // 2^z - features = convert(data, options.tolerance / (z2 * options.extent)); - - this.tiles = {}; - this.tileCoords = []; - - if (debug) { - console.timeEnd('preprocess data'); - console.log('index: maxZoom: %d, maxPoints: %d', options.indexMaxZoom, options.indexMaxPoints); - console.time('generate tiles'); - this.stats = {}; - this.total = 0; + var pos = this.sprite.getSpritePosition(name); + if (!pos.width || !pos.height) { + return null; } - - features = wrap(features, options.buffer / options.extent, intersectX); - - // start slicing from the top tile down - if (features.length) this.splitTile(features, 0, 0, 0); - - if (debug) { - if (features.length) console.log('features: %d, points: %d', this.tiles[0].numFeatures, this.tiles[0].numPoints); - console.timeEnd('generate tiles'); - console.log('tiles generated:', this.total, JSON.stringify(this.stats)); + var rect = this.allocateImage(pos.width, pos.height); + if (!rect) { + return null; } -} - -GeoJSONVT.prototype.options = { - maxZoom: 14, // max zoom to preserve detail on - indexMaxZoom: 5, // max zoom in the tile index - indexMaxPoints: 100000, // max number of points per tile in the tile index - solidChildren: false, // whether to tile solid square tiles further - tolerance: 3, // simplification tolerance (higher means simpler) - extent: 4096, // tile extent - buffer: 64, // tile buffer on each side - debug: 0 // logging level (0, 1 or 2) + var image = new AtlasImage(rect, pos.width / pos.pixelRatio, pos.height / pos.pixelRatio, pos.sdf, pos.pixelRatio / this.pixelRatio); + this.images[name] = image; + this.copy(rect, pos, wrap); + return image; }; - -GeoJSONVT.prototype.splitTile = function (features, z, x, y, cz, cx, cy) { - - var stack = [features, z, x, y], - options = this.options, - debug = options.debug, - solid = null; - - // avoid recursion by using a processing queue - while (stack.length) { - y = stack.pop(); - x = stack.pop(); - z = stack.pop(); - features = stack.pop(); - - var z2 = 1 << z, - id = toID(z, x, y), - tile = this.tiles[id], - tileTolerance = z === options.maxZoom ? 0 : options.tolerance / (z2 * options.extent); - - if (!tile) { - if (debug > 1) console.time('creation'); - - tile = this.tiles[id] = createTile(features, z2, x, y, tileTolerance, z === options.maxZoom); - this.tileCoords.push({z: z, x: x, y: y}); - - if (debug) { - if (debug > 1) { - console.log('tile z%d-%d-%d (features: %d, points: %d, simplified: %d)', - z, x, y, tile.numFeatures, tile.numPoints, tile.numSimplified); - console.timeEnd('creation'); - } - var key = 'z' + z; - this.stats[key] = (this.stats[key] || 0) + 1; - this.total++; - } - } - - // save reference to original geometry in tile so that we can drill down later if we stop now - tile.source = features; - - // if it's the first-pass tiling - if (!cz) { - // stop tiling if we reached max zoom, or if the tile is too simple - if (z === options.indexMaxZoom || tile.numPoints <= options.indexMaxPoints) continue; - - // if a drilldown to a specific tile - } else { - // stop tiling if we reached base zoom or our target tile zoom - if (z === options.maxZoom || z === cz) continue; - - // stop tiling if it's not an ancestor of the target tile - var m = 1 << (cz - z); - if (x !== Math.floor(cx / m) || y !== Math.floor(cy / m)) continue; - } - - // stop tiling if the tile is solid clipped square - if (!options.solidChildren && isClippedSquare(tile, options.extent, options.buffer)) { - if (cz) solid = z; // and remember the zoom if we're drilling down - continue; - } - - // if we slice further down, no need to keep source geometry - tile.source = null; - - if (debug > 1) console.time('clipping'); - - // values we'll use for clipping - var k1 = 0.5 * options.buffer / options.extent, - k2 = 0.5 - k1, - k3 = 0.5 + k1, - k4 = 1 + k1, - tl, bl, tr, br, left, right; - - tl = bl = tr = br = null; - - left = clip(features, z2, x - k1, x + k3, 0, intersectX, tile.min[0], tile.max[0]); - right = clip(features, z2, x + k2, x + k4, 0, intersectX, tile.min[0], tile.max[0]); - - if (left) { - tl = clip(left, z2, y - k1, y + k3, 1, intersectY, tile.min[1], tile.max[1]); - bl = clip(left, z2, y + k2, y + k4, 1, intersectY, tile.min[1], tile.max[1]); +SpriteAtlas.prototype.getPosition = function (name, repeating) { + var image = this.getImage(name, repeating); + var rect = image && image.rect; + if (!rect) { + return null; + } + var width = image.width * image.pixelRatio; + var height = image.height * image.pixelRatio; + var padding = 1; + return { + size: [ + image.width, + image.height + ], + tl: [ + (rect.x + padding) / this.width, + (rect.y + padding) / this.height + ], + br: [ + (rect.x + padding + width) / this.width, + (rect.y + padding + height) / this.height + ] + }; +}; +SpriteAtlas.prototype.allocate = function () { + if (!this.data) { + var w = Math.floor(this.width * this.pixelRatio); + var h = Math.floor(this.height * this.pixelRatio); + this.data = new Uint32Array(w * h); + for (var i = 0; i < this.data.length; i++) { + this.data[i] = 0; } - - if (right) { - tr = clip(right, z2, y - k1, y + k3, 1, intersectY, tile.min[1], tile.max[1]); - br = clip(right, z2, y + k2, y + k4, 1, intersectY, tile.min[1], tile.max[1]); + } +}; +SpriteAtlas.prototype.copy = function (dst, src, wrap) { + if (!this.sprite.img.data) + return; + var srcImg = new Uint32Array(this.sprite.img.data.buffer); + this.allocate(); + var dstImg = this.data; + var padding = 1; + copyBitmap(srcImg, this.sprite.img.width, src.x, src.y, dstImg, this.width * this.pixelRatio, (dst.x + padding) * this.pixelRatio, (dst.y + padding) * this.pixelRatio, src.width, src.height, wrap); + this.dirty = true; +}; +SpriteAtlas.prototype.setSprite = function (sprite) { + if (sprite) { + this.pixelRatio = browser.devicePixelRatio > 1 ? 2 : 1; + if (this.canvas) { + this.canvas.width = this.width * this.pixelRatio; + this.canvas.height = this.height * this.pixelRatio; } - - if (debug > 1) console.timeEnd('clipping'); - - if (tl) stack.push(tl, z + 1, x * 2, y * 2); - if (bl) stack.push(bl, z + 1, x * 2, y * 2 + 1); - if (tr) stack.push(tr, z + 1, x * 2 + 1, y * 2); - if (br) stack.push(br, z + 1, x * 2 + 1, y * 2 + 1); } - - return solid; + this.sprite = sprite; }; - -GeoJSONVT.prototype.getTile = function (z, x, y) { - var options = this.options, - extent = options.extent, - debug = options.debug; - - var z2 = 1 << z; - x = ((x % z2) + z2) % z2; // wrap tile x coordinate - - var id = toID(z, x, y); - if (this.tiles[id]) return transform.tile(this.tiles[id], extent); - - if (debug > 1) console.log('drilling down to z%d-%d-%d', z, x, y); - - var z0 = z, - x0 = x, - y0 = y, - parent; - - while (!parent && z0 > 0) { - z0--; - x0 = Math.floor(x0 / 2); - y0 = Math.floor(y0 / 2); - parent = this.tiles[toID(z0, x0, y0)]; +SpriteAtlas.prototype.addIcons = function (icons, callback) { + for (var i = 0; i < icons.length; i++) { + this.getImage(icons[i]); } - - if (!parent || !parent.source) return null; - - // if we found a parent tile containing the original geometry, we can drill down from it - if (debug > 1) console.log('found parent tile z%d-%d-%d', z0, x0, y0); - - // it parent tile is a solid clipped square, return it instead since it's identical - if (isClippedSquare(parent, extent, options.buffer)) return transform.tile(parent, extent); - - if (debug > 1) console.time('drilling down'); - var solid = this.splitTile(parent.source, z0, x0, y0, z, x, y); - if (debug > 1) console.timeEnd('drilling down'); - - // one of the parent tiles was a solid clipped square - if (solid !== null) { - var m = 1 << (z - solid); - id = toID(solid, Math.floor(x / m), Math.floor(y / m)); + callback(null, this.images); +}; +SpriteAtlas.prototype.bind = function (gl, linear) { + var first = false; + if (!this.texture) { + this.texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this.texture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + first = true; + } else { + gl.bindTexture(gl.TEXTURE_2D, this.texture); + } + var filterVal = linear ? gl.LINEAR : gl.NEAREST; + if (filterVal !== this.filter) { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filterVal); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filterVal); + this.filter = filterVal; + } + if (this.dirty) { + this.allocate(); + if (first) { + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width * this.pixelRatio, this.height * this.pixelRatio, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(this.data.buffer)); + } else { + gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, this.width * this.pixelRatio, this.height * this.pixelRatio, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(this.data.buffer)); + } + this.dirty = false; } - - return this.tiles[id] ? transform.tile(this.tiles[id], extent) : null; }; - -function toID(z, x, y) { - return (((1 << z) * y + x) * 32) + z; -} - -function intersectX(a, b, x) { - return [x, (x - a[0]) * (b[1] - a[1]) / (b[0] - a[0]) + a[1], 1]; -} -function intersectY(a, b, y) { - return [(y - a[1]) * (b[0] - a[0]) / (b[1] - a[1]) + a[0], y, 1]; -} - -function extend(dest, src) { - for (var i in src) dest[i] = src[i]; - return dest; +function AtlasImage(rect, width, height, sdf, pixelRatio) { + this.rect = rect; + this.width = width; + this.height = height; + this.sdf = sdf; + this.pixelRatio = pixelRatio; } - -// checks whether a tile is a whole-area fill after clipping; if it is, there's no sense slicing it further -function isClippedSquare(tile, extent, buffer) { - - var features = tile.source; - if (features.length !== 1) return false; - - var feature = features[0]; - if (feature.type !== 3 || feature.geometry.length > 1) return false; - - var len = feature.geometry[0].length; - if (len !== 5) return false; - - for (var i = 0; i < len; i++) { - var p = transform.point(feature.geometry[0][i], extent, tile.z2, tile.x, tile.y); - if ((p[0] !== -buffer && p[0] !== extent + buffer) || - (p[1] !== -buffer && p[1] !== extent + buffer)) return false; +},{"../util/browser":171,"../util/util":188,"shelf-pack":203}],149:[function(require,module,exports){ +'use strict'; +var StructArrayType = require('../util/struct_array'); +var util = require('../util/util'); +var Point = require('point-geometry'); +var SymbolInstancesArray = module.exports = new StructArrayType({ + members: [ + { + type: 'Uint16', + name: 'textBoxStartIndex' + }, + { + type: 'Uint16', + name: 'textBoxEndIndex' + }, + { + type: 'Uint16', + name: 'iconBoxStartIndex' + }, + { + type: 'Uint16', + name: 'iconBoxEndIndex' + }, + { + type: 'Uint16', + name: 'glyphQuadStartIndex' + }, + { + type: 'Uint16', + name: 'glyphQuadEndIndex' + }, + { + type: 'Uint16', + name: 'iconQuadStartIndex' + }, + { + type: 'Uint16', + name: 'iconQuadEndIndex' + }, + { + type: 'Int16', + name: 'anchorPointX' + }, + { + type: 'Int16', + name: 'anchorPointY' + }, + { + type: 'Int8', + name: 'index' + } + ] +}); +util.extendAll(SymbolInstancesArray.prototype.StructType.prototype, { + get anchorPoint() { + return new Point(this.anchorPointX, this.anchorPointY); } - - return true; -} - -},{"./clip":116,"./convert":117,"./tile":120,"./transform":121,"./wrap":122}],119:[function(require,module,exports){ +}); +},{"../util/struct_array":186,"../util/util":188,"point-geometry":196}],150:[function(require,module,exports){ 'use strict'; - -module.exports = simplify; - -// calculate simplification data using optimized Douglas-Peucker algorithm - -function simplify(points, tolerance) { - - var sqTolerance = tolerance * tolerance, - len = points.length, - first = 0, - last = len - 1, - stack = [], - i, maxSqDist, sqDist, index; - - // always retain the endpoints (1 is the max value) - points[first][2] = 1; - points[last][2] = 1; - - // avoid recursion by using a stack - while (last) { - - maxSqDist = 0; - - for (i = first + 1; i < last; i++) { - sqDist = getSqSegDist(points[i], points[first], points[last]); - - if (sqDist > maxSqDist) { - index = i; - maxSqDist = sqDist; - } +var StructArrayType = require('../util/struct_array'); +var util = require('../util/util'); +var Point = require('point-geometry'); +var SymbolQuad = require('./quads').SymbolQuad; +var SymbolQuadsArray = module.exports = new StructArrayType({ + members: [ + { + type: 'Int16', + name: 'anchorPointX' + }, + { + type: 'Int16', + name: 'anchorPointY' + }, + { + type: 'Float32', + name: 'tlX' + }, + { + type: 'Float32', + name: 'tlY' + }, + { + type: 'Float32', + name: 'trX' + }, + { + type: 'Float32', + name: 'trY' + }, + { + type: 'Float32', + name: 'blX' + }, + { + type: 'Float32', + name: 'blY' + }, + { + type: 'Float32', + name: 'brX' + }, + { + type: 'Float32', + name: 'brY' + }, + { + type: 'Int16', + name: 'texH' + }, + { + type: 'Int16', + name: 'texW' + }, + { + type: 'Int16', + name: 'texX' + }, + { + type: 'Int16', + name: 'texY' + }, + { + type: 'Float32', + name: 'anchorAngle' + }, + { + type: 'Float32', + name: 'glyphAngle' + }, + { + type: 'Float32', + name: 'maxScale' + }, + { + type: 'Float32', + name: 'minScale' } - - if (maxSqDist > sqTolerance) { - points[index][2] = maxSqDist; // save the point importance in squared pixels as a z coordinate - stack.push(first); - stack.push(index); - first = index; - + ] +}); +util.extendAll(SymbolQuadsArray.prototype.StructType.prototype, { + get anchorPoint() { + return new Point(this.anchorPointX, this.anchorPointY); + }, + get SymbolQuad() { + return new SymbolQuad(this.anchorPoint, new Point(this.tlX, this.tlY), new Point(this.trX, this.trY), new Point(this.blX, this.blY), new Point(this.brX, this.brY), { + x: this.texX, + y: this.texY, + h: this.texH, + w: this.texW, + height: this.texH, + width: this.texW + }, this.anchorAngle, this.glyphAngle, this.minScale, this.maxScale); + } +}); +},{"../util/struct_array":186,"../util/util":188,"./quads":145,"point-geometry":196}],151:[function(require,module,exports){ +'use strict'; +var DOM = require('../util/dom'); +var Point = require('point-geometry'); +var handlers = { + scrollZoom: require('./handler/scroll_zoom'), + boxZoom: require('./handler/box_zoom'), + dragRotate: require('./handler/drag_rotate'), + dragPan: require('./handler/drag_pan'), + keyboard: require('./handler/keyboard'), + doubleClickZoom: require('./handler/dblclick_zoom'), + touchZoomRotate: require('./handler/touch_zoom_rotate') +}; +module.exports = function bindHandlers(map, options) { + var el = map.getCanvasContainer(); + var contextMenuEvent = null; + var startPos = null; + var tapped = null; + for (var name in handlers) { + map[name] = new handlers[name](map, options); + if (options.interactive && options[name]) { + map[name].enable(); + } + } + el.addEventListener('mouseout', onMouseOut, false); + el.addEventListener('mousedown', onMouseDown, false); + el.addEventListener('mouseup', onMouseUp, false); + el.addEventListener('mousemove', onMouseMove, false); + el.addEventListener('touchstart', onTouchStart, false); + el.addEventListener('touchend', onTouchEnd, false); + el.addEventListener('touchmove', onTouchMove, false); + el.addEventListener('touchcancel', onTouchCancel, false); + el.addEventListener('click', onClick, false); + el.addEventListener('dblclick', onDblClick, false); + el.addEventListener('contextmenu', onContextMenu, false); + function onMouseOut(e) { + fireMouseEvent('mouseout', e); + } + function onMouseDown(e) { + map.stop(); + startPos = DOM.mousePos(el, e); + fireMouseEvent('mousedown', e); + } + function onMouseUp(e) { + var rotating = map.dragRotate && map.dragRotate.isActive(); + if (contextMenuEvent && !rotating) { + fireMouseEvent('contextmenu', contextMenuEvent); + } + contextMenuEvent = null; + fireMouseEvent('mouseup', e); + } + function onMouseMove(e) { + if (map.dragPan && map.dragPan.isActive()) + return; + if (map.dragRotate && map.dragRotate.isActive()) + return; + var target = e.toElement || e.target; + while (target && target !== el) + target = target.parentNode; + if (target !== el) + return; + fireMouseEvent('mousemove', e); + } + function onTouchStart(e) { + map.stop(); + fireTouchEvent('touchstart', e); + if (!e.touches || e.touches.length > 1) + return; + if (!tapped) { + tapped = setTimeout(onTouchTimeout, 300); } else { - last = stack.pop(); - first = stack.pop(); + clearTimeout(tapped); + tapped = null; + fireMouseEvent('dblclick', e); } } -} - -// square distance from a point to a segment -function getSqSegDist(p, a, b) { - - var x = a[0], y = a[1], - bx = b[0], by = b[1], - px = p[0], py = p[1], - dx = bx - x, - dy = by - y; - - if (dx !== 0 || dy !== 0) { - - var t = ((px - x) * dx + (py - y) * dy) / (dx * dx + dy * dy); - - if (t > 1) { - x = bx; - y = by; - - } else if (t > 0) { - x += dx * t; - y += dy * t; + function onTouchMove(e) { + fireTouchEvent('touchmove', e); + } + function onTouchEnd(e) { + fireTouchEvent('touchend', e); + } + function onTouchCancel(e) { + fireTouchEvent('touchcancel', e); + } + function onTouchTimeout() { + tapped = null; + } + function onClick(e) { + var pos = DOM.mousePos(el, e); + if (pos.equals(startPos)) { + fireMouseEvent('click', e); } } - - dx = px - x; - dy = py - y; - - return dx * dx + dy * dy; -} - -},{}],120:[function(require,module,exports){ -'use strict'; - -module.exports = createTile; - -function createTile(features, z2, tx, ty, tolerance, noSimplify) { - var tile = { - features: [], - numPoints: 0, - numSimplified: 0, - numFeatures: 0, - source: null, - x: tx, - y: ty, - z2: z2, - transformed: false, - min: [2, 1], - max: [-1, 0] - }; - for (var i = 0; i < features.length; i++) { - tile.numFeatures++; - addFeature(tile, features[i], tolerance, noSimplify); - - var min = features[i].min, - max = features[i].max; - - if (min[0] < tile.min[0]) tile.min[0] = min[0]; - if (min[1] < tile.min[1]) tile.min[1] = min[1]; - if (max[0] > tile.max[0]) tile.max[0] = max[0]; - if (max[1] > tile.max[1]) tile.max[1] = max[1]; + function onDblClick(e) { + fireMouseEvent('dblclick', e); + e.preventDefault(); } - return tile; -} - -function addFeature(tile, feature, tolerance, noSimplify) { - - var geom = feature.geometry, - type = feature.type, - simplified = [], - sqTolerance = tolerance * tolerance, - i, j, ring, p; - - if (type === 1) { - for (i = 0; i < geom.length; i++) { - simplified.push(geom[i]); - tile.numPoints++; - tile.numSimplified++; - } - - } else { - - // simplify and transform projected coordinates for tile geometry - for (i = 0; i < geom.length; i++) { - ring = geom[i]; - - // filter out tiny polylines & polygons - if (!noSimplify && ((type === 2 && ring.dist < tolerance) || - (type === 3 && ring.area < sqTolerance))) { - tile.numPoints += ring.length; - continue; - } - - var simplifiedRing = []; - - for (j = 0; j < ring.length; j++) { - p = ring[j]; - // keep points with importance > tolerance - if (noSimplify || p[2] > sqTolerance) { - simplifiedRing.push(p); - tile.numSimplified++; - } - tile.numPoints++; - } - - simplified.push(simplifiedRing); - } + function onContextMenu(e) { + contextMenuEvent = e; + e.preventDefault(); } - - if (simplified.length) { - tile.features.push({ - geometry: simplified, - type: type, - tags: feature.tags || null + function fireMouseEvent(type, e) { + var pos = DOM.mousePos(el, e); + return map.fire(type, { + lngLat: map.unproject(pos), + point: pos, + originalEvent: e }); } -} - -},{}],121:[function(require,module,exports){ -'use strict'; - -exports.tile = transformTile; -exports.point = transformPoint; - -// Transforms the coordinates of each feature in the given tile from -// mercator-projected space into (extent x extent) tile space. -function transformTile(tile, extent) { - if (tile.transformed) return tile; - - var z2 = tile.z2, - tx = tile.x, - ty = tile.y, - i, j, k; - - for (i = 0; i < tile.features.length; i++) { - var feature = tile.features[i], - geom = feature.geometry, - type = feature.type; - - if (type === 1) { - for (j = 0; j < geom.length; j++) geom[j] = transformPoint(geom[j], extent, z2, tx, ty); - - } else { - for (j = 0; j < geom.length; j++) { - var ring = geom[j]; - for (k = 0; k < ring.length; k++) ring[k] = transformPoint(ring[k], extent, z2, tx, ty); - } - } + function fireTouchEvent(type, e) { + var touches = DOM.touchPos(el, e); + var singular = touches.reduce(function (prev, curr, i, arr) { + return prev.add(curr.div(arr.length)); + }, new Point(0, 0)); + return map.fire(type, { + lngLat: map.unproject(singular), + point: singular, + lngLats: touches.map(function (t) { + return map.unproject(t); + }, this), + points: touches, + originalEvent: e + }); } - - tile.transformed = true; - - return tile; -} - -function transformPoint(p, extent, z2, tx, ty) { - var x = Math.round(extent * (p[0] * z2 - tx)), - y = Math.round(extent * (p[1] * z2 - ty)); - return [x, y]; -} - -},{}],122:[function(require,module,exports){ +}; +},{"../util/dom":178,"./handler/box_zoom":158,"./handler/dblclick_zoom":159,"./handler/drag_pan":160,"./handler/drag_rotate":161,"./handler/keyboard":162,"./handler/scroll_zoom":163,"./handler/touch_zoom_rotate":164,"point-geometry":196}],152:[function(require,module,exports){ 'use strict'; - -var clip = require('./clip'); - -module.exports = wrap; - -function wrap(features, buffer, intersectX) { - var merged = features, - left = clip(features, 1, -1 - buffer, buffer, 0, intersectX, -1, 2), // left world copy - right = clip(features, 1, 1 - buffer, 2 + buffer, 0, intersectX, -1, 2); // right world copy - - if (left || right) { - merged = clip(features, 1, -buffer, 1 + buffer, 0, intersectX, -1, 2); // center world copy - - if (left) merged = shiftFeatureCoords(left, 1).concat(merged); // merge left into center - if (right) merged = merged.concat(shiftFeatureCoords(right, -1)); // merge right into center - } - - return merged; -} - -function shiftFeatureCoords(features, offset) { - var newFeatures = []; - - for (var i = 0; i < features.length; i++) { - var feature = features[i], - type = feature.type; - - var newGeometry; - - if (type === 1) { - newGeometry = shiftCoords(feature.geometry, offset); +var util = require('../util/util'); +var interpolate = require('../util/interpolate'); +var browser = require('../util/browser'); +var LngLat = require('../geo/lng_lat'); +var LngLatBounds = require('../geo/lng_lat_bounds'); +var Point = require('point-geometry'); +var Camera = module.exports = function () { +}; +util.extend(Camera.prototype, { + getCenter: function () { + return this.transform.center; + }, + setCenter: function (center, eventData) { + this.jumpTo({ center: center }, eventData); + return this; + }, + panBy: function (offset, options, eventData) { + this.panTo(this.transform.center, util.extend({ offset: Point.convert(offset).mult(-1) }, options), eventData); + return this; + }, + panTo: function (lnglat, options, eventData) { + return this.easeTo(util.extend({ center: lnglat }, options), eventData); + }, + getZoom: function () { + return this.transform.zoom; + }, + setZoom: function (zoom, eventData) { + this.jumpTo({ zoom: zoom }, eventData); + return this; + }, + zoomTo: function (zoom, options, eventData) { + return this.easeTo(util.extend({ zoom: zoom }, options), eventData); + }, + zoomIn: function (options, eventData) { + this.zoomTo(this.getZoom() + 1, options, eventData); + return this; + }, + zoomOut: function (options, eventData) { + this.zoomTo(this.getZoom() - 1, options, eventData); + return this; + }, + getBearing: function () { + return this.transform.bearing; + }, + setBearing: function (bearing, eventData) { + this.jumpTo({ bearing: bearing }, eventData); + return this; + }, + rotateTo: function (bearing, options, eventData) { + return this.easeTo(util.extend({ bearing: bearing }, options), eventData); + }, + resetNorth: function (options, eventData) { + this.rotateTo(0, util.extend({ duration: 1000 }, options), eventData); + return this; + }, + snapToNorth: function (options, eventData) { + if (Math.abs(this.getBearing()) < this._bearingSnap) { + return this.resetNorth(options, eventData); + } + return this; + }, + getPitch: function () { + return this.transform.pitch; + }, + setPitch: function (pitch, eventData) { + this.jumpTo({ pitch: pitch }, eventData); + return this; + }, + fitBounds: function (bounds, options, eventData) { + options = util.extend({ + padding: 0, + offset: [ + 0, + 0 + ], + maxZoom: Infinity + }, options); + bounds = LngLatBounds.convert(bounds); + var offset = Point.convert(options.offset), tr = this.transform, nw = tr.project(bounds.getNorthWest()), se = tr.project(bounds.getSouthEast()), size = se.sub(nw), scaleX = (tr.width - options.padding * 2 - Math.abs(offset.x) * 2) / size.x, scaleY = (tr.height - options.padding * 2 - Math.abs(offset.y) * 2) / size.y; + options.center = tr.unproject(nw.add(se).div(2)); + options.zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom); + options.bearing = 0; + return options.linear ? this.easeTo(options, eventData) : this.flyTo(options, eventData); + }, + jumpTo: function (options, eventData) { + this.stop(); + var tr = this.transform, zoomChanged = false, bearingChanged = false, pitchChanged = false; + if ('zoom' in options && tr.zoom !== +options.zoom) { + zoomChanged = true; + tr.zoom = +options.zoom; + } + if ('center' in options) { + tr.center = LngLat.convert(options.center); + } + if ('bearing' in options && tr.bearing !== +options.bearing) { + bearingChanged = true; + tr.bearing = +options.bearing; + } + if ('pitch' in options && tr.pitch !== +options.pitch) { + pitchChanged = true; + tr.pitch = +options.pitch; + } + this.fire('movestart', eventData).fire('move', eventData); + if (zoomChanged) { + this.fire('zoomstart', eventData).fire('zoom', eventData).fire('zoomend', eventData); + } + if (bearingChanged) { + this.fire('rotate', eventData); + } + if (pitchChanged) { + this.fire('pitch', eventData); + } + return this.fire('moveend', eventData); + }, + easeTo: function (options, eventData) { + this.stop(); + options = util.extend({ + offset: [ + 0, + 0 + ], + duration: 500, + easing: util.ease + }, options); + var tr = this.transform, offset = Point.convert(options.offset), startZoom = this.getZoom(), startBearing = this.getBearing(), startPitch = this.getPitch(), zoom = 'zoom' in options ? +options.zoom : startZoom, bearing = 'bearing' in options ? this._normalizeBearing(options.bearing, startBearing) : startBearing, pitch = 'pitch' in options ? +options.pitch : startPitch, toLngLat, toPoint; + if ('center' in options) { + toLngLat = LngLat.convert(options.center); + toPoint = tr.centerPoint.add(offset); + } else if ('around' in options) { + toLngLat = LngLat.convert(options.around); + toPoint = tr.locationPoint(toLngLat); } else { - newGeometry = []; - for (var j = 0; j < feature.geometry.length; j++) { - newGeometry.push(shiftCoords(feature.geometry[j], offset)); - } + toPoint = tr.centerPoint.add(offset); + toLngLat = tr.pointLocation(toPoint); + } + var fromPoint = tr.locationPoint(toLngLat); + if (options.animate === false) + options.duration = 0; + this.zooming = zoom !== startZoom; + this.rotating = startBearing !== bearing; + this.pitching = pitch !== startPitch; + if (options.smoothEasing && options.duration !== 0) { + options.easing = this._smoothOutEasing(options.duration); } - - newFeatures.push({ - geometry: newGeometry, - type: type, - tags: feature.tags, - min: [feature.min[0] + offset, feature.min[1]], - max: [feature.max[0] + offset, feature.max[1]] - }); - } - - return newFeatures; -} - -function shiftCoords(points, offset) { - var newPoints = []; - newPoints.area = points.area; - newPoints.dist = points.dist; - - for (var i = 0; i < points.length; i++) { - newPoints.push([points[i][0] + offset, points[i][1], points[i][2]]); + if (!options.noMoveStart) { + this.fire('movestart', eventData); + } + if (this.zooming) { + this.fire('zoomstart', eventData); + } + clearTimeout(this._onEaseEnd); + this._ease(function (k) { + if (this.zooming) { + tr.zoom = interpolate(startZoom, zoom, k); + } + if (this.rotating) { + tr.bearing = interpolate(startBearing, bearing, k); + } + if (this.pitching) { + tr.pitch = interpolate(startPitch, pitch, k); + } + tr.setLocationAtPoint(toLngLat, fromPoint.add(toPoint.sub(fromPoint)._mult(k))); + this.fire('move', eventData); + if (this.zooming) { + this.fire('zoom', eventData); + } + if (this.rotating) { + this.fire('rotate', eventData); + } + if (this.pitching) { + this.fire('pitch', eventData); + } + }, function () { + if (options.delayEndEvents) { + this._onEaseEnd = setTimeout(this._easeToEnd.bind(this, eventData), options.delayEndEvents); + } else { + this._easeToEnd(eventData); + } + }.bind(this), options); + return this; + }, + _easeToEnd: function (eventData) { + var wasZooming = this.zooming; + this.zooming = false; + this.rotating = false; + this.pitching = false; + if (wasZooming) { + this.fire('zoomend', eventData); + } + this.fire('moveend', eventData); + }, + flyTo: function (options, eventData) { + this.stop(); + options = util.extend({ + offset: [ + 0, + 0 + ], + speed: 1.2, + curve: 1.42, + easing: util.ease + }, options); + var tr = this.transform, offset = Point.convert(options.offset), startZoom = this.getZoom(), startBearing = this.getBearing(), startPitch = this.getPitch(); + var center = 'center' in options ? LngLat.convert(options.center) : this.getCenter(); + var zoom = 'zoom' in options ? +options.zoom : startZoom; + var bearing = 'bearing' in options ? this._normalizeBearing(options.bearing, startBearing) : startBearing; + var pitch = 'pitch' in options ? +options.pitch : startPitch; + if (Math.abs(tr.center.lng) + Math.abs(center.lng) > 180) { + if (tr.center.lng > 0 && center.lng < 0) { + center.lng += 360; + } else if (tr.center.lng < 0 && center.lng > 0) { + center.lng -= 360; + } + } + var scale = tr.zoomScale(zoom - startZoom), from = tr.point, to = 'center' in options ? tr.project(center).sub(offset.div(scale)) : from; + var startWorldSize = tr.worldSize, rho = options.curve, w0 = Math.max(tr.width, tr.height), w1 = w0 / scale, u1 = to.sub(from).mag(); + if ('minZoom' in options) { + var minZoom = util.clamp(Math.min(options.minZoom, startZoom, zoom), tr.minZoom, tr.maxZoom); + var wMax = w0 / tr.zoomScale(minZoom - startZoom); + rho = Math.sqrt(wMax / u1 * 2); + } + var rho2 = rho * rho; + function r(i) { + var b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1); + return Math.log(Math.sqrt(b * b + 1) - b); + } + function sinh(n) { + return (Math.exp(n) - Math.exp(-n)) / 2; + } + function cosh(n) { + return (Math.exp(n) + Math.exp(-n)) / 2; + } + function tanh(n) { + return sinh(n) / cosh(n); + } + var r0 = r(0), w = function (s) { + return cosh(r0) / cosh(r0 + rho * s); + }, u = function (s) { + return w0 * ((cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2) / u1; + }, S = (r(1) - r0) / rho; + if (Math.abs(u1) < 0.000001) { + if (Math.abs(w0 - w1) < 0.000001) + return this.easeTo(options); + var k = w1 < w0 ? -1 : 1; + S = Math.abs(Math.log(w1 / w0)) / rho; + u = function () { + return 0; + }; + w = function (s) { + return Math.exp(k * rho * s); + }; + } + if ('duration' in options) { + options.duration = +options.duration; + } else { + var V = 'screenSpeed' in options ? +options.screenSpeed / rho : +options.speed; + options.duration = 1000 * S / V; + } + this.zooming = true; + if (startBearing !== bearing) + this.rotating = true; + if (startPitch !== pitch) + this.pitching = true; + this.fire('movestart', eventData); + this.fire('zoomstart', eventData); + this._ease(function (k) { + var s = k * S, us = u(s); + tr.zoom = startZoom + tr.scaleZoom(1 / w(s)); + tr.center = tr.unproject(from.add(to.sub(from).mult(us)), startWorldSize); + if (this.rotating) { + tr.bearing = interpolate(startBearing, bearing, k); + } + if (this.pitching) { + tr.pitch = interpolate(startPitch, pitch, k); + } + this.fire('move', eventData); + this.fire('zoom', eventData); + if (this.rotating) { + this.fire('rotate', eventData); + } + if (this.pitching) { + this.fire('pitch', eventData); + } + }, function () { + this.zooming = false; + this.rotating = false; + this.pitching = false; + this.fire('zoomend', eventData); + this.fire('moveend', eventData); + }, options); + return this; + }, + isEasing: function () { + return !!this._abortFn; + }, + stop: function () { + if (this._abortFn) { + this._abortFn(); + this._finishEase(); + } + return this; + }, + _ease: function (frame, finish, options) { + this._finishFn = finish; + this._abortFn = browser.timed(function (t) { + frame.call(this, options.easing(t)); + if (t === 1) { + this._finishEase(); + } + }, options.animate === false ? 0 : options.duration, this); + }, + _finishEase: function () { + delete this._abortFn; + var finish = this._finishFn; + delete this._finishFn; + finish.call(this); + }, + _normalizeBearing: function (bearing, currentBearing) { + bearing = util.wrap(bearing, -180, 180); + var diff = Math.abs(bearing - currentBearing); + if (Math.abs(bearing - 360 - currentBearing) < diff) + bearing -= 360; + if (Math.abs(bearing + 360 - currentBearing) < diff) + bearing += 360; + return bearing; + }, + _smoothOutEasing: function (duration) { + var easing = util.ease; + if (this._prevEase) { + var ease = this._prevEase, t = (Date.now() - ease.start) / ease.duration, speed = ease.easing(t + 0.01) - ease.easing(t), x = 0.27 / Math.sqrt(speed * speed + 0.0001) * 0.01, y = Math.sqrt(0.27 * 0.27 - x * x); + easing = util.bezier(x, y, 0.25, 1); + } + this._prevEase = { + start: new Date().getTime(), + duration: duration, + easing: easing + }; + return easing; } - return newPoints; +}); +},{"../geo/lng_lat":82,"../geo/lng_lat_bounds":83,"../util/browser":171,"../util/interpolate":182,"../util/util":188,"point-geometry":196}],153:[function(require,module,exports){ +'use strict'; +var Control = require('./control'); +var DOM = require('../../util/dom'); +var util = require('../../util/util'); +module.exports = Attribution; +function Attribution(options) { + util.setOptions(this, options); } - -},{"./clip":116}],123:[function(require,module,exports){ -/** - * @fileoverview gl-matrix - High performance matrix and vector operations - * @author Brandon Jones - * @author Colin MacKenzie IV - * @version 2.3.0 - */ - -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -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. */ -// END HEADER - -exports.glMatrix = require("./gl-matrix/common.js"); -exports.mat2 = require("./gl-matrix/mat2.js"); -exports.mat2d = require("./gl-matrix/mat2d.js"); -exports.mat3 = require("./gl-matrix/mat3.js"); -exports.mat4 = require("./gl-matrix/mat4.js"); -exports.quat = require("./gl-matrix/quat.js"); -exports.vec2 = require("./gl-matrix/vec2.js"); -exports.vec3 = require("./gl-matrix/vec3.js"); -exports.vec4 = require("./gl-matrix/vec4.js"); -},{"./gl-matrix/common.js":124,"./gl-matrix/mat2.js":125,"./gl-matrix/mat2d.js":126,"./gl-matrix/mat3.js":127,"./gl-matrix/mat4.js":128,"./gl-matrix/quat.js":129,"./gl-matrix/vec2.js":130,"./gl-matrix/vec3.js":131,"./gl-matrix/vec4.js":132}],124:[function(require,module,exports){ -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -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. */ - -/** - * @class Common utilities - * @name glMatrix - */ -var glMatrix = {}; - -// Constants -glMatrix.EPSILON = 0.000001; -glMatrix.ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array; -glMatrix.RANDOM = Math.random; - -/** - * Sets the type of array used when creating new vectors and matrices - * - * @param {Type} type Array type, such as Float32Array or Array - */ -glMatrix.setMatrixArrayType = function(type) { - GLMAT_ARRAY_TYPE = type; +Attribution.prototype = util.inherit(Control, { + options: { position: 'bottom-right' }, + onAdd: function (map) { + var className = 'mapboxgl-ctrl-attrib', container = this._container = DOM.create('div', className, map.getContainer()); + this._updateAttributions(); + this._updateEditLink(); + map.on('data', function (event) { + if (event.dataType === 'source') { + this._updateAttributions(); + this._updateEditLink(); + } + }.bind(this)); + map.on('moveend', this._updateEditLink.bind(this)); + return container; + }, + _updateAttributions: function () { + if (!this._map.style) + return; + var attributions = []; + var sourceCaches = this._map.style.sourceCaches; + for (var id in sourceCaches) { + var source = sourceCaches[id].getSource(); + if (source.attribution && attributions.indexOf(source.attribution) < 0) { + attributions.push(source.attribution); + } + } + attributions.sort(function (a, b) { + return a.length - b.length; + }); + attributions = attributions.filter(function (attrib, i) { + for (var j = i + 1; j < attributions.length; j++) { + if (attributions[j].indexOf(attrib) >= 0) { + return false; + } + } + return true; + }); + this._container.innerHTML = attributions.join(' | '); + }, + _updateEditLink: function () { + if (this._editLink) { + var center = this._map.getCenter(); + this._editLink.href = 'https://www.mapbox.com/map-feedback/#/' + center.lng + '/' + center.lat + '/' + Math.round(this._map.getZoom() + 1); + } + } +}); +},{"../../util/dom":178,"../../util/util":188,"./control":154}],154:[function(require,module,exports){ +'use strict'; +var util = require('../../util/util'); +var Evented = require('../../util/evented'); +module.exports = Control; +function Control() { } - -var degree = Math.PI / 180; - -/** -* Convert Degree To Radian -* -* @param {Number} Angle in Degrees -*/ -glMatrix.toRadian = function(a){ - return a * degree; -} - -module.exports = glMatrix; - -},{}],125:[function(require,module,exports){ -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -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. */ - -var glMatrix = require("./common.js"); - -/** - * @class 2x2 Matrix - * @name mat2 - */ -var mat2 = {}; - -/** - * Creates a new identity mat2 - * - * @returns {mat2} a new 2x2 matrix - */ -mat2.create = function() { - var out = new glMatrix.ARRAY_TYPE(4); - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 1; - return out; -}; - -/** - * Creates a new mat2 initialized with values from an existing matrix - * - * @param {mat2} a matrix to clone - * @returns {mat2} a new 2x2 matrix - */ -mat2.clone = function(a) { - var out = new glMatrix.ARRAY_TYPE(4); - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - return out; -}; - -/** - * Copy the values from one mat2 to another - * - * @param {mat2} out the receiving matrix - * @param {mat2} a the source matrix - * @returns {mat2} out - */ -mat2.copy = function(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - return out; +Control.prototype = { + addTo: function (map) { + this._map = map; + var container = this._container = this.onAdd(map); + if (this.options && this.options.position) { + var pos = this.options.position; + var corner = map._controlCorners[pos]; + container.className += ' mapboxgl-ctrl'; + if (pos.indexOf('bottom') !== -1) { + corner.insertBefore(container, corner.firstChild); + } else { + corner.appendChild(container); + } + } + return this; + }, + remove: function () { + this._container.parentNode.removeChild(this._container); + if (this.onRemove) + this.onRemove(this._map); + this._map = null; + return this; + } }; - -/** - * Set a mat2 to the identity matrix - * - * @param {mat2} out the receiving matrix - * @returns {mat2} out - */ -mat2.identity = function(out) { - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 1; - return out; +util.extend(Control.prototype, Evented); +},{"../../util/evented":179,"../../util/util":188}],155:[function(require,module,exports){ +'use strict'; +var Control = require('./control'); +var browser = require('../../util/browser'); +var DOM = require('../../util/dom'); +var util = require('../../util/util'); +var window = require('../../util/window'); +module.exports = Geolocate; +var geoOptions = { + enableHighAccuracy: false, + timeout: 6000 }; - -/** - * Transpose the values of a mat2 - * - * @param {mat2} out the receiving matrix - * @param {mat2} a the source matrix - * @returns {mat2} out - */ -mat2.transpose = function(out, a) { - // If we are transposing ourselves we can skip a few steps but have to cache some values - if (out === a) { - var a1 = a[1]; - out[1] = a[2]; - out[2] = a1; +function Geolocate(options) { + util.setOptions(this, options); +} +Geolocate.prototype = util.inherit(Control, { + options: { position: 'top-right' }, + onAdd: function (map) { + var className = 'mapboxgl-ctrl'; + var container = this._container = DOM.create('div', className + '-group', map.getContainer()); + if (!browser.supportsGeolocation) + return container; + this._container.addEventListener('contextmenu', this._onContextMenu.bind(this)); + this._geolocateButton = DOM.create('button', className + '-icon ' + className + '-geolocate', this._container); + this._geolocateButton.type = 'button'; + this._geolocateButton.addEventListener('click', this._onClickGeolocate.bind(this)); + return container; + }, + _onContextMenu: function (e) { + e.preventDefault(); + }, + _onClickGeolocate: function () { + window.navigator.geolocation.getCurrentPosition(this._success.bind(this), this._error.bind(this), geoOptions); + this._timeoutId = setTimeout(this._finish.bind(this), 10000); + }, + _success: function (position) { + this._map.jumpTo({ + center: [ + position.coords.longitude, + position.coords.latitude + ], + zoom: 17, + bearing: 0, + pitch: 0 + }); + this.fire('geolocate', position); + this._finish(); + }, + _error: function (error) { + this.fire('error', error); + this._finish(); + }, + _finish: function () { + if (this._timeoutId) { + clearTimeout(this._timeoutId); + } + this._timeoutId = undefined; + } +}); +},{"../../util/browser":171,"../../util/dom":178,"../../util/util":188,"../../util/window":173,"./control":154}],156:[function(require,module,exports){ +'use strict'; +var Control = require('./control'); +var DOM = require('../../util/dom'); +var util = require('../../util/util'); +var window = require('../../util/window'); +module.exports = Navigation; +function Navigation(options) { + util.setOptions(this, options); +} +Navigation.prototype = util.inherit(Control, { + options: { position: 'top-right' }, + onAdd: function (map) { + var className = 'mapboxgl-ctrl'; + var container = this._container = DOM.create('div', className + '-group', map.getContainer()); + this._container.addEventListener('contextmenu', this._onContextMenu.bind(this)); + this._zoomInButton = this._createButton(className + '-icon ' + className + '-zoom-in', map.zoomIn.bind(map)); + this._zoomOutButton = this._createButton(className + '-icon ' + className + '-zoom-out', map.zoomOut.bind(map)); + this._compass = this._createButton(className + '-icon ' + className + '-compass', map.resetNorth.bind(map)); + this._compassArrow = DOM.create('span', 'arrow', this._compass); + this._compass.addEventListener('mousedown', this._onCompassDown.bind(this)); + this._onCompassMove = this._onCompassMove.bind(this); + this._onCompassUp = this._onCompassUp.bind(this); + map.on('rotate', this._rotateCompassArrow.bind(this)); + this._rotateCompassArrow(); + this._el = map.getCanvasContainer(); + return container; + }, + _onContextMenu: function (e) { + e.preventDefault(); + }, + _onCompassDown: function (e) { + if (e.button !== 0) + return; + DOM.disableDrag(); + window.document.addEventListener('mousemove', this._onCompassMove); + window.document.addEventListener('mouseup', this._onCompassUp); + this._el.dispatchEvent(copyMouseEvent(e)); + e.stopPropagation(); + }, + _onCompassMove: function (e) { + if (e.button !== 0) + return; + this._el.dispatchEvent(copyMouseEvent(e)); + e.stopPropagation(); + }, + _onCompassUp: function (e) { + if (e.button !== 0) + return; + window.document.removeEventListener('mousemove', this._onCompassMove); + window.document.removeEventListener('mouseup', this._onCompassUp); + DOM.enableDrag(); + this._el.dispatchEvent(copyMouseEvent(e)); + e.stopPropagation(); + }, + _createButton: function (className, fn) { + var a = DOM.create('button', className, this._container); + a.type = 'button'; + a.addEventListener('click', function () { + fn(); + }); + return a; + }, + _rotateCompassArrow: function () { + var rotate = 'rotate(' + this._map.transform.angle * (180 / Math.PI) + 'deg)'; + this._compassArrow.style.transform = rotate; + } +}); +function copyMouseEvent(e) { + return new window.MouseEvent(e.type, { + button: 2, + buttons: 2, + bubbles: true, + cancelable: true, + detail: e.detail, + view: e.view, + screenX: e.screenX, + screenY: e.screenY, + clientX: e.clientX, + clientY: e.clientY, + movementX: e.movementX, + movementY: e.movementY, + ctrlKey: e.ctrlKey, + shiftKey: e.shiftKey, + altKey: e.altKey, + metaKey: e.metaKey + }); +} +},{"../../util/dom":178,"../../util/util":188,"../../util/window":173,"./control":154}],157:[function(require,module,exports){ +'use strict'; +var util = require('../../util/util'); +var Control = require('./control'); +var DOM = require('../../util/dom'); +module.exports = Scale; +function Scale(options) { + util.setOptions(this, options); +} +Scale.prototype = util.inherit(Control, { + options: { position: 'bottom-left' }, + onAdd: function (map) { + var className = 'mapboxgl-ctrl-scale', container = this._container = DOM.create('div', className, map.getContainer()), options = this.options; + updateScale(map, container, options); + map.on('move', function () { + updateScale(map, container, options); + }); + return container; + } +}); +function updateScale(map, scale, options) { + var maxWidth = options && options.maxWidth || 100; + var y = map._container.clientHeight / 2; + var maxMeters = getDistance(map.unproject([ + 0, + y + ]), map.unproject([ + maxWidth, + y + ])); + if (options && options.unit === 'imperial') { + var maxFeet = 3.2808 * maxMeters; + if (maxFeet > 5280) { + var maxMiles = maxFeet / 5280; + setScale(scale, maxWidth, maxMiles, 'mi'); + } else { + setScale(scale, maxWidth, maxFeet, 'ft'); + } } else { - out[0] = a[0]; - out[1] = a[2]; - out[2] = a[1]; - out[3] = a[3]; + setScale(scale, maxWidth, maxMeters, 'm'); } - - return out; -}; - -/** - * Inverts a mat2 - * - * @param {mat2} out the receiving matrix - * @param {mat2} a the source matrix - * @returns {mat2} out - */ -mat2.invert = function(out, a) { - var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], - - // Calculate the determinant - det = a0 * a3 - a2 * a1; - - if (!det) { - return null; +} +function setScale(scale, maxWidth, maxDistance, unit) { + var distance = getRoundNum(maxDistance); + var ratio = distance / maxDistance; + if (unit === 'm' && distance >= 1000) { + distance = distance / 1000; + unit = 'km'; } - det = 1.0 / det; - - out[0] = a3 * det; - out[1] = -a1 * det; - out[2] = -a2 * det; - out[3] = a0 * det; - - return out; -}; - -/** - * Calculates the adjugate of a mat2 - * - * @param {mat2} out the receiving matrix - * @param {mat2} a the source matrix - * @returns {mat2} out - */ -mat2.adjoint = function(out, a) { - // Caching this value is nessecary if out == a - var a0 = a[0]; - out[0] = a[3]; - out[1] = -a[1]; - out[2] = -a[2]; - out[3] = a0; - - return out; -}; - -/** - * Calculates the determinant of a mat2 - * - * @param {mat2} a the source matrix - * @returns {Number} determinant of a - */ -mat2.determinant = function (a) { - return a[0] * a[3] - a[2] * a[1]; -}; - -/** - * Multiplies two mat2's - * - * @param {mat2} out the receiving matrix - * @param {mat2} a the first operand - * @param {mat2} b the second operand - * @returns {mat2} out - */ -mat2.multiply = function (out, a, b) { - var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; - var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; - out[0] = a0 * b0 + a2 * b1; - out[1] = a1 * b0 + a3 * b1; - out[2] = a0 * b2 + a2 * b3; - out[3] = a1 * b2 + a3 * b3; - return out; -}; - -/** - * Alias for {@link mat2.multiply} - * @function - */ -mat2.mul = mat2.multiply; - -/** - * Rotates a mat2 by the given angle - * - * @param {mat2} out the receiving matrix - * @param {mat2} a the matrix to rotate - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat2} out - */ -mat2.rotate = function (out, a, rad) { - var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], - s = Math.sin(rad), - c = Math.cos(rad); - out[0] = a0 * c + a2 * s; - out[1] = a1 * c + a3 * s; - out[2] = a0 * -s + a2 * c; - out[3] = a1 * -s + a3 * c; - return out; -}; - -/** - * Scales the mat2 by the dimensions in the given vec2 - * - * @param {mat2} out the receiving matrix - * @param {mat2} a the matrix to rotate - * @param {vec2} v the vec2 to scale the matrix by - * @returns {mat2} out - **/ -mat2.scale = function(out, a, v) { - var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], - v0 = v[0], v1 = v[1]; - out[0] = a0 * v0; - out[1] = a1 * v0; - out[2] = a2 * v1; - out[3] = a3 * v1; - return out; -}; - -/** - * Creates a matrix from a given angle - * This is equivalent to (but much faster than): - * - * mat2.identity(dest); - * mat2.rotate(dest, dest, rad); - * - * @param {mat2} out mat2 receiving operation result - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat2} out - */ -mat2.fromRotation = function(out, rad) { - var s = Math.sin(rad), - c = Math.cos(rad); - out[0] = c; - out[1] = s; - out[2] = -s; - out[3] = c; - return out; + scale.style.width = maxWidth * ratio + 'px'; + scale.innerHTML = distance + unit; } - -/** - * Creates a matrix from a vector scaling - * This is equivalent to (but much faster than): - * - * mat2.identity(dest); - * mat2.scale(dest, dest, vec); - * - * @param {mat2} out mat2 receiving operation result - * @param {vec2} v Scaling vector - * @returns {mat2} out - */ -mat2.fromScaling = function(out, v) { - out[0] = v[0]; - out[1] = 0; - out[2] = 0; - out[3] = v[1]; - return out; +function getDistance(latlng1, latlng2) { + var R = 6371000; + var rad = Math.PI / 180, lat1 = latlng1.lat * rad, lat2 = latlng2.lat * rad, a = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos((latlng2.lng - latlng1.lng) * rad); + var maxMeters = R * Math.acos(Math.min(a, 1)); + return maxMeters; } - -/** - * Returns a string representation of a mat2 - * - * @param {mat2} mat matrix to represent as a string - * @returns {String} string representation of the matrix - */ -mat2.str = function (a) { - return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; +function getRoundNum(num) { + var pow10 = Math.pow(10, (Math.floor(num) + '').length - 1), d = num / pow10; + d = d >= 10 ? 10 : d >= 5 ? 5 : d >= 3 ? 3 : d >= 2 ? 2 : 1; + return pow10 * d; +} +},{"../../util/dom":178,"../../util/util":188,"./control":154}],158:[function(require,module,exports){ +'use strict'; +var DOM = require('../../util/dom'); +var LngLatBounds = require('../../geo/lng_lat_bounds'); +var util = require('../../util/util'); +var window = require('../../util/window'); +module.exports = BoxZoomHandler; +function BoxZoomHandler(map) { + this._map = map; + this._el = map.getCanvasContainer(); + this._container = map.getContainer(); + util.bindHandlers(this); +} +BoxZoomHandler.prototype = { + _enabled: false, + _active: false, + isEnabled: function () { + return this._enabled; + }, + isActive: function () { + return this._active; + }, + enable: function () { + if (this.isEnabled()) + return; + this._el.addEventListener('mousedown', this._onMouseDown, false); + this._enabled = true; + }, + disable: function () { + if (!this.isEnabled()) + return; + this._el.removeEventListener('mousedown', this._onMouseDown); + this._enabled = false; + }, + _onMouseDown: function (e) { + if (!(e.shiftKey && e.button === 0)) + return; + window.document.addEventListener('mousemove', this._onMouseMove, false); + window.document.addEventListener('keydown', this._onKeyDown, false); + window.document.addEventListener('mouseup', this._onMouseUp, false); + DOM.disableDrag(); + this._startPos = DOM.mousePos(this._el, e); + this._active = true; + }, + _onMouseMove: function (e) { + var p0 = this._startPos, p1 = DOM.mousePos(this._el, e); + if (!this._box) { + this._box = DOM.create('div', 'mapboxgl-boxzoom', this._container); + this._container.classList.add('mapboxgl-crosshair'); + this._fireEvent('boxzoomstart', e); + } + var minX = Math.min(p0.x, p1.x), maxX = Math.max(p0.x, p1.x), minY = Math.min(p0.y, p1.y), maxY = Math.max(p0.y, p1.y); + DOM.setTransform(this._box, 'translate(' + minX + 'px,' + minY + 'px)'); + this._box.style.width = maxX - minX + 'px'; + this._box.style.height = maxY - minY + 'px'; + }, + _onMouseUp: function (e) { + if (e.button !== 0) + return; + var p0 = this._startPos, p1 = DOM.mousePos(this._el, e), bounds = new LngLatBounds().extend(this._map.unproject(p0)).extend(this._map.unproject(p1)); + this._finish(); + if (p0.x === p1.x && p0.y === p1.y) { + this._fireEvent('boxzoomcancel', e); + } else { + this._map.fitBounds(bounds, { linear: true }).fire('boxzoomend', { + originalEvent: e, + boxZoomBounds: bounds + }); + } + }, + _onKeyDown: function (e) { + if (e.keyCode === 27) { + this._finish(); + this._fireEvent('boxzoomcancel', e); + } + }, + _finish: function () { + this._active = false; + window.document.removeEventListener('mousemove', this._onMouseMove, false); + window.document.removeEventListener('keydown', this._onKeyDown, false); + window.document.removeEventListener('mouseup', this._onMouseUp, false); + this._container.classList.remove('mapboxgl-crosshair'); + if (this._box) { + this._box.parentNode.removeChild(this._box); + this._box = null; + } + DOM.enableDrag(); + }, + _fireEvent: function (type, e) { + return this._map.fire(type, { originalEvent: e }); + } }; - -/** - * Returns Frobenius norm of a mat2 - * - * @param {mat2} a the matrix to calculate Frobenius norm of - * @returns {Number} Frobenius norm - */ -mat2.frob = function (a) { - return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2))) +},{"../../geo/lng_lat_bounds":83,"../../util/dom":178,"../../util/util":188,"../../util/window":173}],159:[function(require,module,exports){ +'use strict'; +module.exports = DoubleClickZoomHandler; +function DoubleClickZoomHandler(map) { + this._map = map; + this._onDblClick = this._onDblClick.bind(this); +} +DoubleClickZoomHandler.prototype = { + _enabled: false, + isEnabled: function () { + return this._enabled; + }, + enable: function () { + if (this.isEnabled()) + return; + this._map.on('dblclick', this._onDblClick); + this._enabled = true; + }, + disable: function () { + if (!this.isEnabled()) + return; + this._map.off('dblclick', this._onDblClick); + this._enabled = false; + }, + _onDblClick: function (e) { + this._map.zoomTo(this._map.getZoom() + (e.originalEvent.shiftKey ? -1 : 1), { around: e.lngLat }, e); + } }; - -/** - * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix - * @param {mat2} L the lower triangular matrix - * @param {mat2} D the diagonal matrix - * @param {mat2} U the upper triangular matrix - * @param {mat2} a the input matrix to factorize - */ - -mat2.LDU = function (L, D, U, a) { - L[2] = a[2]/a[0]; - U[0] = a[0]; - U[1] = a[1]; - U[3] = a[3] - L[2] * U[1]; - return [L, D, U]; -}; - - -module.exports = mat2; - -},{"./common.js":124}],126:[function(require,module,exports){ -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -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. */ - -var glMatrix = require("./common.js"); - -/** - * @class 2x3 Matrix - * @name mat2d - * - * @description - * A mat2d contains six elements defined as: - *
- * [a, c, tx,
- *  b, d, ty]
- * 
- * This is a short form for the 3x3 matrix: - *
- * [a, c, tx,
- *  b, d, ty,
- *  0, 0, 1]
- * 
- * The last row is ignored so the array is shorter and operations are faster. - */ -var mat2d = {}; - -/** - * Creates a new identity mat2d - * - * @returns {mat2d} a new 2x3 matrix - */ -mat2d.create = function() { - var out = new glMatrix.ARRAY_TYPE(6); - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 1; - out[4] = 0; - out[5] = 0; - return out; -}; - -/** - * Creates a new mat2d initialized with values from an existing matrix - * - * @param {mat2d} a matrix to clone - * @returns {mat2d} a new 2x3 matrix - */ -mat2d.clone = function(a) { - var out = new glMatrix.ARRAY_TYPE(6); - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[4] = a[4]; - out[5] = a[5]; - return out; -}; - -/** - * Copy the values from one mat2d to another - * - * @param {mat2d} out the receiving matrix - * @param {mat2d} a the source matrix - * @returns {mat2d} out - */ -mat2d.copy = function(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[4] = a[4]; - out[5] = a[5]; - return out; -}; - -/** - * Set a mat2d to the identity matrix - * - * @param {mat2d} out the receiving matrix - * @returns {mat2d} out - */ -mat2d.identity = function(out) { - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 1; - out[4] = 0; - out[5] = 0; - return out; -}; - -/** - * Inverts a mat2d - * - * @param {mat2d} out the receiving matrix - * @param {mat2d} a the source matrix - * @returns {mat2d} out - */ -mat2d.invert = function(out, a) { - var aa = a[0], ab = a[1], ac = a[2], ad = a[3], - atx = a[4], aty = a[5]; - - var det = aa * ad - ab * ac; - if(!det){ - return null; +},{}],160:[function(require,module,exports){ +'use strict'; +var DOM = require('../../util/dom'); +var util = require('../../util/util'); +var window = require('../../util/window'); +module.exports = DragPanHandler; +var inertiaLinearity = 0.3, inertiaEasing = util.bezier(0, 0, inertiaLinearity, 1), inertiaMaxSpeed = 1400, inertiaDeceleration = 2500; +function DragPanHandler(map) { + this._map = map; + this._el = map.getCanvasContainer(); + util.bindHandlers(this); +} +DragPanHandler.prototype = { + _enabled: false, + _active: false, + isEnabled: function () { + return this._enabled; + }, + isActive: function () { + return this._active; + }, + enable: function () { + if (this.isEnabled()) + return; + this._el.addEventListener('mousedown', this._onDown); + this._el.addEventListener('touchstart', this._onDown); + this._enabled = true; + }, + disable: function () { + if (!this.isEnabled()) + return; + this._el.removeEventListener('mousedown', this._onDown); + this._el.removeEventListener('touchstart', this._onDown); + this._enabled = false; + }, + _onDown: function (e) { + if (this._ignoreEvent(e)) + return; + if (this.isActive()) + return; + if (e.touches) { + window.document.addEventListener('touchmove', this._onMove); + window.document.addEventListener('touchend', this._onTouchEnd); + } else { + window.document.addEventListener('mousemove', this._onMove); + window.document.addEventListener('mouseup', this._onMouseUp); + } + this._active = false; + this._startPos = this._pos = DOM.mousePos(this._el, e); + this._inertia = [[ + Date.now(), + this._pos + ]]; + }, + _onMove: function (e) { + if (this._ignoreEvent(e)) + return; + if (!this.isActive()) { + this._active = true; + this._fireEvent('dragstart', e); + this._fireEvent('movestart', e); + } + var pos = DOM.mousePos(this._el, e), map = this._map; + map.stop(); + this._drainInertiaBuffer(); + this._inertia.push([ + Date.now(), + pos + ]); + map.transform.setLocationAtPoint(map.transform.pointLocation(this._pos), pos); + this._fireEvent('drag', e); + this._fireEvent('move', e); + this._pos = pos; + e.preventDefault(); + }, + _onUp: function (e) { + if (!this.isActive()) + return; + this._active = false; + this._fireEvent('dragend', e); + this._drainInertiaBuffer(); + var finish = function () { + this._fireEvent('moveend', e); + }.bind(this); + var inertia = this._inertia; + if (inertia.length < 2) { + finish(); + return; + } + var last = inertia[inertia.length - 1], first = inertia[0], flingOffset = last[1].sub(first[1]), flingDuration = (last[0] - first[0]) / 1000; + if (flingDuration === 0 || last[1].equals(first[1])) { + finish(); + return; + } + var velocity = flingOffset.mult(inertiaLinearity / flingDuration), speed = velocity.mag(); + if (speed > inertiaMaxSpeed) { + speed = inertiaMaxSpeed; + velocity._unit()._mult(speed); + } + var duration = speed / (inertiaDeceleration * inertiaLinearity), offset = velocity.mult(-duration / 2); + this._map.panBy(offset, { + duration: duration * 1000, + easing: inertiaEasing, + noMoveStart: true + }, { originalEvent: e }); + }, + _onMouseUp: function (e) { + if (this._ignoreEvent(e)) + return; + this._onUp(e); + window.document.removeEventListener('mousemove', this._onMove); + window.document.removeEventListener('mouseup', this._onMouseUp); + }, + _onTouchEnd: function (e) { + if (this._ignoreEvent(e)) + return; + this._onUp(e); + window.document.removeEventListener('touchmove', this._onMove); + window.document.removeEventListener('touchend', this._onTouchEnd); + }, + _fireEvent: function (type, e) { + return this._map.fire(type, { originalEvent: e }); + }, + _ignoreEvent: function (e) { + var map = this._map; + if (map.boxZoom && map.boxZoom.isActive()) + return true; + if (map.dragRotate && map.dragRotate.isActive()) + return true; + if (e.touches) { + return e.touches.length > 1; + } else { + if (e.ctrlKey) + return true; + var buttons = 1, button = 0; + return e.type === 'mousemove' ? e.buttons & buttons === 0 : e.button !== button; + } + }, + _drainInertiaBuffer: function () { + var inertia = this._inertia, now = Date.now(), cutoff = 160; + while (inertia.length > 0 && now - inertia[0][0] > cutoff) + inertia.shift(); } - det = 1.0 / det; - - out[0] = ad * det; - out[1] = -ab * det; - out[2] = -ac * det; - out[3] = aa * det; - out[4] = (ac * aty - ad * atx) * det; - out[5] = (ab * atx - aa * aty) * det; - return out; -}; - -/** - * Calculates the determinant of a mat2d - * - * @param {mat2d} a the source matrix - * @returns {Number} determinant of a - */ -mat2d.determinant = function (a) { - return a[0] * a[3] - a[1] * a[2]; -}; - -/** - * Multiplies two mat2d's - * - * @param {mat2d} out the receiving matrix - * @param {mat2d} a the first operand - * @param {mat2d} b the second operand - * @returns {mat2d} out - */ -mat2d.multiply = function (out, a, b) { - var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], - b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5]; - out[0] = a0 * b0 + a2 * b1; - out[1] = a1 * b0 + a3 * b1; - out[2] = a0 * b2 + a2 * b3; - out[3] = a1 * b2 + a3 * b3; - out[4] = a0 * b4 + a2 * b5 + a4; - out[5] = a1 * b4 + a3 * b5 + a5; - return out; }; - -/** - * Alias for {@link mat2d.multiply} - * @function - */ -mat2d.mul = mat2d.multiply; - -/** - * Rotates a mat2d by the given angle - * - * @param {mat2d} out the receiving matrix - * @param {mat2d} a the matrix to rotate - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat2d} out - */ -mat2d.rotate = function (out, a, rad) { - var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], - s = Math.sin(rad), - c = Math.cos(rad); - out[0] = a0 * c + a2 * s; - out[1] = a1 * c + a3 * s; - out[2] = a0 * -s + a2 * c; - out[3] = a1 * -s + a3 * c; - out[4] = a4; - out[5] = a5; - return out; -}; - -/** - * Scales the mat2d by the dimensions in the given vec2 - * - * @param {mat2d} out the receiving matrix - * @param {mat2d} a the matrix to translate - * @param {vec2} v the vec2 to scale the matrix by - * @returns {mat2d} out - **/ -mat2d.scale = function(out, a, v) { - var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], - v0 = v[0], v1 = v[1]; - out[0] = a0 * v0; - out[1] = a1 * v0; - out[2] = a2 * v1; - out[3] = a3 * v1; - out[4] = a4; - out[5] = a5; - return out; -}; - -/** - * Translates the mat2d by the dimensions in the given vec2 - * - * @param {mat2d} out the receiving matrix - * @param {mat2d} a the matrix to translate - * @param {vec2} v the vec2 to translate the matrix by - * @returns {mat2d} out - **/ -mat2d.translate = function(out, a, v) { - var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], - v0 = v[0], v1 = v[1]; - out[0] = a0; - out[1] = a1; - out[2] = a2; - out[3] = a3; - out[4] = a0 * v0 + a2 * v1 + a4; - out[5] = a1 * v0 + a3 * v1 + a5; - return out; -}; - -/** - * Creates a matrix from a given angle - * This is equivalent to (but much faster than): - * - * mat2d.identity(dest); - * mat2d.rotate(dest, dest, rad); - * - * @param {mat2d} out mat2d receiving operation result - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat2d} out - */ -mat2d.fromRotation = function(out, rad) { - var s = Math.sin(rad), c = Math.cos(rad); - out[0] = c; - out[1] = s; - out[2] = -s; - out[3] = c; - out[4] = 0; - out[5] = 0; - return out; +},{"../../util/dom":178,"../../util/util":188,"../../util/window":173}],161:[function(require,module,exports){ +'use strict'; +var DOM = require('../../util/dom'); +var util = require('../../util/util'); +var window = require('../../util/window'); +module.exports = DragRotateHandler; +var inertiaLinearity = 0.25, inertiaEasing = util.bezier(0, 0, inertiaLinearity, 1), inertiaMaxSpeed = 180, inertiaDeceleration = 720; +function DragRotateHandler(map, options) { + this._map = map; + this._el = map.getCanvasContainer(); + this._bearingSnap = options.bearingSnap; + this._pitchWithRotate = options.pitchWithRotate !== false; + util.bindHandlers(this); } - -/** - * Creates a matrix from a vector scaling - * This is equivalent to (but much faster than): - * - * mat2d.identity(dest); - * mat2d.scale(dest, dest, vec); - * - * @param {mat2d} out mat2d receiving operation result - * @param {vec2} v Scaling vector - * @returns {mat2d} out - */ -mat2d.fromScaling = function(out, v) { - out[0] = v[0]; - out[1] = 0; - out[2] = 0; - out[3] = v[1]; - out[4] = 0; - out[5] = 0; - return out; +DragRotateHandler.prototype = { + _enabled: false, + _active: false, + isEnabled: function () { + return this._enabled; + }, + isActive: function () { + return this._active; + }, + enable: function () { + if (this.isEnabled()) + return; + this._el.addEventListener('mousedown', this._onDown); + this._enabled = true; + }, + disable: function () { + if (!this.isEnabled()) + return; + this._el.removeEventListener('mousedown', this._onDown); + this._enabled = false; + }, + _onDown: function (e) { + if (this._ignoreEvent(e)) + return; + if (this.isActive()) + return; + window.document.addEventListener('mousemove', this._onMove); + window.document.addEventListener('mouseup', this._onUp); + this._active = false; + this._inertia = [[ + Date.now(), + this._map.getBearing() + ]]; + this._startPos = this._pos = DOM.mousePos(this._el, e); + this._center = this._map.transform.centerPoint; + e.preventDefault(); + }, + _onMove: function (e) { + if (this._ignoreEvent(e)) + return; + if (!this.isActive()) { + this._active = true; + this._fireEvent('rotatestart', e); + this._fireEvent('movestart', e); + } + var map = this._map; + map.stop(); + var p1 = this._pos, p2 = DOM.mousePos(this._el, e), bearingDiff = (p1.x - p2.x) * 0.8, pitchDiff = (p1.y - p2.y) * -0.5, bearing = map.getBearing() - bearingDiff, pitch = map.getPitch() - pitchDiff, inertia = this._inertia, last = inertia[inertia.length - 1]; + this._drainInertiaBuffer(); + inertia.push([ + Date.now(), + map._normalizeBearing(bearing, last[1]) + ]); + map.transform.bearing = bearing; + if (this._pitchWithRotate) + map.transform.pitch = pitch; + this._fireEvent('rotate', e); + this._fireEvent('move', e); + this._pos = p2; + }, + _onUp: function (e) { + if (this._ignoreEvent(e)) + return; + window.document.removeEventListener('mousemove', this._onMove); + window.document.removeEventListener('mouseup', this._onUp); + if (!this.isActive()) + return; + this._active = false; + this._fireEvent('rotateend', e); + this._drainInertiaBuffer(); + var map = this._map, mapBearing = map.getBearing(), inertia = this._inertia; + var finish = function () { + if (Math.abs(mapBearing) < this._bearingSnap) { + map.resetNorth({ noMoveStart: true }, { originalEvent: e }); + } else { + this._fireEvent('moveend', e); + } + }.bind(this); + if (inertia.length < 2) { + finish(); + return; + } + var first = inertia[0], last = inertia[inertia.length - 1], previous = inertia[inertia.length - 2], bearing = map._normalizeBearing(mapBearing, previous[1]), flingDiff = last[1] - first[1], sign = flingDiff < 0 ? -1 : 1, flingDuration = (last[0] - first[0]) / 1000; + if (flingDiff === 0 || flingDuration === 0) { + finish(); + return; + } + var speed = Math.abs(flingDiff * (inertiaLinearity / flingDuration)); + if (speed > inertiaMaxSpeed) { + speed = inertiaMaxSpeed; + } + var duration = speed / (inertiaDeceleration * inertiaLinearity), offset = sign * speed * (duration / 2); + bearing += offset; + if (Math.abs(map._normalizeBearing(bearing, 0)) < this._bearingSnap) { + bearing = map._normalizeBearing(0, bearing); + } + map.rotateTo(bearing, { + duration: duration * 1000, + easing: inertiaEasing, + noMoveStart: true + }, { originalEvent: e }); + }, + _fireEvent: function (type, e) { + return this._map.fire(type, { originalEvent: e }); + }, + _ignoreEvent: function (e) { + var map = this._map; + if (map.boxZoom && map.boxZoom.isActive()) + return true; + if (map.dragPan && map.dragPan.isActive()) + return true; + if (e.touches) { + return e.touches.length > 1; + } else { + var buttons = e.ctrlKey ? 1 : 2, button = e.ctrlKey ? 0 : 2; + return e.type === 'mousemove' ? e.buttons & buttons === 0 : e.button !== button; + } + }, + _drainInertiaBuffer: function () { + var inertia = this._inertia, now = Date.now(), cutoff = 160; + while (inertia.length > 0 && now - inertia[0][0] > cutoff) + inertia.shift(); + } +}; +},{"../../util/dom":178,"../../util/util":188,"../../util/window":173}],162:[function(require,module,exports){ +'use strict'; +module.exports = KeyboardHandler; +var panStep = 100, bearingStep = 15, pitchStep = 10; +function KeyboardHandler(map) { + this._map = map; + this._el = map.getCanvasContainer(); + this._onKeyDown = this._onKeyDown.bind(this); } - -/** - * Creates a matrix from a vector translation - * This is equivalent to (but much faster than): - * - * mat2d.identity(dest); - * mat2d.translate(dest, dest, vec); - * - * @param {mat2d} out mat2d receiving operation result - * @param {vec2} v Translation vector - * @returns {mat2d} out - */ -mat2d.fromTranslation = function(out, v) { - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 1; - out[4] = v[0]; - out[5] = v[1]; - return out; +function easeOut(t) { + return t * (2 - t); } - -/** - * Returns a string representation of a mat2d - * - * @param {mat2d} a matrix to represent as a string - * @returns {String} string representation of the matrix - */ -mat2d.str = function (a) { - return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + - a[3] + ', ' + a[4] + ', ' + a[5] + ')'; +KeyboardHandler.prototype = { + _enabled: false, + isEnabled: function () { + return this._enabled; + }, + enable: function () { + if (this.isEnabled()) + return; + this._el.addEventListener('keydown', this._onKeyDown, false); + this._enabled = true; + }, + disable: function () { + if (!this.isEnabled()) + return; + this._el.removeEventListener('keydown', this._onKeyDown); + this._enabled = false; + }, + _onKeyDown: function (e) { + if (e.altKey || e.ctrlKey || e.metaKey) + return; + var zoomDir = 0; + var bearingDir = 0; + var pitchDir = 0; + var xDir = 0; + var yDir = 0; + switch (e.keyCode) { + case 61: + case 107: + case 171: + case 187: + zoomDir = 1; + break; + case 189: + case 109: + case 173: + zoomDir = -1; + break; + case 37: + if (e.shiftKey) { + bearingDir = -1; + } else { + e.preventDefault(); + xDir = -1; + } + break; + case 39: + if (e.shiftKey) { + bearingDir = 1; + } else { + e.preventDefault(); + xDir = 1; + } + break; + case 38: + if (e.shiftKey) { + pitchDir = 1; + } else { + e.preventDefault(); + yDir = -1; + } + break; + case 40: + if (e.shiftKey) { + pitchDir = -1; + } else { + yDir = 1; + e.preventDefault(); + } + break; + } + var map = this._map; + var zoom = map.getZoom(); + var easeOptions = { + duration: 300, + delayEndEvents: 500, + easing: easeOut, + zoom: zoomDir ? Math.round(zoom) + zoomDir * (e.shiftKey ? 2 : 1) : zoom, + bearing: map.getBearing() + bearingDir * bearingStep, + pitch: map.getPitch() + pitchDir * pitchStep, + offset: [ + -xDir * panStep, + -yDir * panStep + ], + center: map.getCenter() + }; + map.easeTo(easeOptions, { originalEvent: e }); + } }; - -/** - * Returns Frobenius norm of a mat2d - * - * @param {mat2d} a the matrix to calculate Frobenius norm of - * @returns {Number} Frobenius norm - */ -mat2d.frob = function (a) { - return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1)) -}; - -module.exports = mat2d; - -},{"./common.js":124}],127:[function(require,module,exports){ -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -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. */ - -var glMatrix = require("./common.js"); - -/** - * @class 3x3 Matrix - * @name mat3 - */ -var mat3 = {}; - -/** - * Creates a new identity mat3 - * - * @returns {mat3} a new 3x3 matrix - */ -mat3.create = function() { - var out = new glMatrix.ARRAY_TYPE(9); - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 1; - out[5] = 0; - out[6] = 0; - out[7] = 0; - out[8] = 1; - return out; -}; - -/** - * Copies the upper-left 3x3 values into the given mat3. - * - * @param {mat3} out the receiving 3x3 matrix - * @param {mat4} a the source 4x4 matrix - * @returns {mat3} out - */ -mat3.fromMat4 = function(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[4]; - out[4] = a[5]; - out[5] = a[6]; - out[6] = a[8]; - out[7] = a[9]; - out[8] = a[10]; - return out; -}; - -/** - * Creates a new mat3 initialized with values from an existing matrix - * - * @param {mat3} a matrix to clone - * @returns {mat3} a new 3x3 matrix - */ -mat3.clone = function(a) { - var out = new glMatrix.ARRAY_TYPE(9); - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[4] = a[4]; - out[5] = a[5]; - out[6] = a[6]; - out[7] = a[7]; - out[8] = a[8]; - return out; -}; - -/** - * Copy the values from one mat3 to another - * - * @param {mat3} out the receiving matrix - * @param {mat3} a the source matrix - * @returns {mat3} out - */ -mat3.copy = function(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[4] = a[4]; - out[5] = a[5]; - out[6] = a[6]; - out[7] = a[7]; - out[8] = a[8]; - return out; -}; - -/** - * Set a mat3 to the identity matrix - * - * @param {mat3} out the receiving matrix - * @returns {mat3} out - */ -mat3.identity = function(out) { - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 1; - out[5] = 0; - out[6] = 0; - out[7] = 0; - out[8] = 1; - return out; -}; - -/** - * Transpose the values of a mat3 - * - * @param {mat3} out the receiving matrix - * @param {mat3} a the source matrix - * @returns {mat3} out - */ -mat3.transpose = function(out, a) { - // If we are transposing ourselves we can skip a few steps but have to cache some values - if (out === a) { - var a01 = a[1], a02 = a[2], a12 = a[5]; - out[1] = a[3]; - out[2] = a[6]; - out[3] = a01; - out[5] = a[7]; - out[6] = a02; - out[7] = a12; - } else { - out[0] = a[0]; - out[1] = a[3]; - out[2] = a[6]; - out[3] = a[1]; - out[4] = a[4]; - out[5] = a[7]; - out[6] = a[2]; - out[7] = a[5]; - out[8] = a[8]; +},{}],163:[function(require,module,exports){ +'use strict'; +var DOM = require('../../util/dom'); +var util = require('../../util/util'); +var browser = require('../../util/browser'); +var window = require('../../util/window'); +module.exports = ScrollZoomHandler; +var ua = window.navigator.userAgent.toLowerCase(), firefox = ua.indexOf('firefox') !== -1, safari = ua.indexOf('safari') !== -1 && ua.indexOf('chrom') === -1; +function ScrollZoomHandler(map) { + this._map = map; + this._el = map.getCanvasContainer(); + util.bindHandlers(this); +} +ScrollZoomHandler.prototype = { + _enabled: false, + isEnabled: function () { + return this._enabled; + }, + enable: function () { + if (this.isEnabled()) + return; + this._el.addEventListener('wheel', this._onWheel, false); + this._el.addEventListener('mousewheel', this._onWheel, false); + this._enabled = true; + }, + disable: function () { + if (!this.isEnabled()) + return; + this._el.removeEventListener('wheel', this._onWheel); + this._el.removeEventListener('mousewheel', this._onWheel); + this._enabled = false; + }, + _onWheel: function (e) { + var value; + if (e.type === 'wheel') { + value = e.deltaY; + if (firefox && e.deltaMode === window.WheelEvent.DOM_DELTA_PIXEL) + value /= browser.devicePixelRatio; + if (e.deltaMode === window.WheelEvent.DOM_DELTA_LINE) + value *= 40; + } else if (e.type === 'mousewheel') { + value = -e.wheelDeltaY; + if (safari) + value = value / 3; + } + var now = browser.now(), timeDelta = now - (this._time || 0); + this._pos = DOM.mousePos(this._el, e); + this._time = now; + if (value !== 0 && value % 4.000244140625 === 0) { + this._type = 'wheel'; + } else if (value !== 0 && Math.abs(value) < 4) { + this._type = 'trackpad'; + } else if (timeDelta > 400) { + this._type = null; + this._lastValue = value; + this._timeout = setTimeout(this._onTimeout, 40); + } else if (!this._type) { + this._type = Math.abs(timeDelta * value) < 200 ? 'trackpad' : 'wheel'; + if (this._timeout) { + clearTimeout(this._timeout); + this._timeout = null; + value += this._lastValue; + } + } + if (e.shiftKey && value) + value = value / 4; + if (this._type) + this._zoom(-value, e); + e.preventDefault(); + }, + _onTimeout: function () { + this._type = 'wheel'; + this._zoom(-this._lastValue); + }, + _zoom: function (delta, e) { + if (delta === 0) + return; + var map = this._map; + var scale = 2 / (1 + Math.exp(-Math.abs(delta / 100))); + if (delta < 0 && scale !== 0) + scale = 1 / scale; + var fromScale = map.ease ? map.ease.to : map.transform.scale, targetZoom = map.transform.scaleZoom(fromScale * scale); + map.zoomTo(targetZoom, { + duration: this._type === 'wheel' ? 200 : 0, + around: map.unproject(this._pos), + delayEndEvents: 200, + smoothEasing: true + }, { originalEvent: e }); } - - return out; }; - -/** - * Inverts a mat3 - * - * @param {mat3} out the receiving matrix - * @param {mat3} a the source matrix - * @returns {mat3} out - */ -mat3.invert = function(out, a) { - var a00 = a[0], a01 = a[1], a02 = a[2], - a10 = a[3], a11 = a[4], a12 = a[5], - a20 = a[6], a21 = a[7], a22 = a[8], - - b01 = a22 * a11 - a12 * a21, - b11 = -a22 * a10 + a12 * a20, - b21 = a21 * a10 - a11 * a20, - - // Calculate the determinant - det = a00 * b01 + a01 * b11 + a02 * b21; - - if (!det) { - return null; - } - det = 1.0 / det; - - out[0] = b01 * det; - out[1] = (-a22 * a01 + a02 * a21) * det; - out[2] = (a12 * a01 - a02 * a11) * det; - out[3] = b11 * det; - out[4] = (a22 * a00 - a02 * a20) * det; - out[5] = (-a12 * a00 + a02 * a10) * det; - out[6] = b21 * det; - out[7] = (-a21 * a00 + a01 * a20) * det; - out[8] = (a11 * a00 - a01 * a10) * det; - return out; -}; - -/** - * Calculates the adjugate of a mat3 - * - * @param {mat3} out the receiving matrix - * @param {mat3} a the source matrix - * @returns {mat3} out - */ -mat3.adjoint = function(out, a) { - var a00 = a[0], a01 = a[1], a02 = a[2], - a10 = a[3], a11 = a[4], a12 = a[5], - a20 = a[6], a21 = a[7], a22 = a[8]; - - out[0] = (a11 * a22 - a12 * a21); - out[1] = (a02 * a21 - a01 * a22); - out[2] = (a01 * a12 - a02 * a11); - out[3] = (a12 * a20 - a10 * a22); - out[4] = (a00 * a22 - a02 * a20); - out[5] = (a02 * a10 - a00 * a12); - out[6] = (a10 * a21 - a11 * a20); - out[7] = (a01 * a20 - a00 * a21); - out[8] = (a00 * a11 - a01 * a10); - return out; +},{"../../util/browser":171,"../../util/dom":178,"../../util/util":188,"../../util/window":173}],164:[function(require,module,exports){ +'use strict'; +var DOM = require('../../util/dom'); +var util = require('../../util/util'); +var window = require('../../util/window'); +module.exports = TouchZoomRotateHandler; +var inertiaLinearity = 0.15, inertiaEasing = util.bezier(0, 0, inertiaLinearity, 1), inertiaDeceleration = 12, inertiaMaxSpeed = 2.5, significantScaleThreshold = 0.15, significantRotateThreshold = 4; +function TouchZoomRotateHandler(map) { + this._map = map; + this._el = map.getCanvasContainer(); + util.bindHandlers(this); +} +TouchZoomRotateHandler.prototype = { + _enabled: false, + isEnabled: function () { + return this._enabled; + }, + enable: function () { + if (this.isEnabled()) + return; + this._el.addEventListener('touchstart', this._onStart, false); + this._enabled = true; + }, + disable: function () { + if (!this.isEnabled()) + return; + this._el.removeEventListener('touchstart', this._onStart); + this._enabled = false; + }, + disableRotation: function () { + this._rotationDisabled = true; + }, + enableRotation: function () { + this._rotationDisabled = false; + }, + _onStart: function (e) { + if (e.touches.length !== 2) + return; + var p0 = DOM.mousePos(this._el, e.touches[0]), p1 = DOM.mousePos(this._el, e.touches[1]); + this._startVec = p0.sub(p1); + this._startScale = this._map.transform.scale; + this._startBearing = this._map.transform.bearing; + this._gestureIntent = undefined; + this._inertia = []; + window.document.addEventListener('touchmove', this._onMove, false); + window.document.addEventListener('touchend', this._onEnd, false); + }, + _onMove: function (e) { + if (e.touches.length !== 2) + return; + var p0 = DOM.mousePos(this._el, e.touches[0]), p1 = DOM.mousePos(this._el, e.touches[1]), p = p0.add(p1).div(2), vec = p0.sub(p1), scale = vec.mag() / this._startVec.mag(), bearing = this._rotationDisabled ? 0 : vec.angleWith(this._startVec) * 180 / Math.PI, map = this._map; + if (!this._gestureIntent) { + var scalingSignificantly = Math.abs(1 - scale) > significantScaleThreshold, rotatingSignificantly = Math.abs(bearing) > significantRotateThreshold; + if (rotatingSignificantly) { + this._gestureIntent = 'rotate'; + } else if (scalingSignificantly) { + this._gestureIntent = 'zoom'; + } + if (this._gestureIntent) { + this._startVec = vec; + this._startScale = map.transform.scale; + this._startBearing = map.transform.bearing; + } + } else { + var param = { + duration: 0, + around: map.unproject(p) + }; + if (this._gestureIntent === 'rotate') { + param.bearing = this._startBearing + bearing; + } + if (this._gestureIntent === 'zoom' || this._gestureIntent === 'rotate') { + param.zoom = map.transform.scaleZoom(this._startScale * scale); + } + map.stop(); + this._drainInertiaBuffer(); + this._inertia.push([ + Date.now(), + scale, + p + ]); + map.easeTo(param, { originalEvent: e }); + } + e.preventDefault(); + }, + _onEnd: function (e) { + window.document.removeEventListener('touchmove', this._onMove); + window.document.removeEventListener('touchend', this._onEnd); + this._drainInertiaBuffer(); + var inertia = this._inertia, map = this._map; + if (inertia.length < 2) { + map.snapToNorth({}, { originalEvent: e }); + return; + } + var last = inertia[inertia.length - 1], first = inertia[0], lastScale = map.transform.scaleZoom(this._startScale * last[1]), firstScale = map.transform.scaleZoom(this._startScale * first[1]), scaleOffset = lastScale - firstScale, scaleDuration = (last[0] - first[0]) / 1000, p = last[2]; + if (scaleDuration === 0 || lastScale === firstScale) { + map.snapToNorth({}, { originalEvent: e }); + return; + } + var speed = scaleOffset * inertiaLinearity / scaleDuration; + if (Math.abs(speed) > inertiaMaxSpeed) { + if (speed > 0) { + speed = inertiaMaxSpeed; + } else { + speed = -inertiaMaxSpeed; + } + } + var duration = Math.abs(speed / (inertiaDeceleration * inertiaLinearity)) * 1000, targetScale = lastScale + speed * duration / 2000; + if (targetScale < 0) { + targetScale = 0; + } + map.easeTo({ + zoom: targetScale, + duration: duration, + easing: inertiaEasing, + around: map.unproject(p) + }, { originalEvent: e }); + }, + _drainInertiaBuffer: function () { + var inertia = this._inertia, now = Date.now(), cutoff = 160; + while (inertia.length > 2 && now - inertia[0][0] > cutoff) + inertia.shift(); + } }; - -/** - * Calculates the determinant of a mat3 - * - * @param {mat3} a the source matrix - * @returns {Number} determinant of a - */ -mat3.determinant = function (a) { - var a00 = a[0], a01 = a[1], a02 = a[2], - a10 = a[3], a11 = a[4], a12 = a[5], - a20 = a[6], a21 = a[7], a22 = a[8]; - - return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20); +},{"../../util/dom":178,"../../util/util":188,"../../util/window":173}],165:[function(require,module,exports){ +'use strict'; +module.exports = Hash; +var util = require('../util/util'); +var window = require('../util/window'); +function Hash() { + util.bindAll([ + '_onHashChange', + '_updateHash' + ], this); +} +Hash.prototype = { + addTo: function (map) { + this._map = map; + window.addEventListener('hashchange', this._onHashChange, false); + this._map.on('moveend', this._updateHash); + return this; + }, + remove: function () { + window.removeEventListener('hashchange', this._onHashChange, false); + this._map.off('moveend', this._updateHash); + delete this._map; + return this; + }, + _onHashChange: function () { + var loc = window.location.hash.replace('#', '').split('/'); + if (loc.length >= 3) { + this._map.jumpTo({ + center: [ + +loc[2], + +loc[1] + ], + zoom: +loc[0], + bearing: +(loc[3] || 0), + pitch: +(loc[4] || 0) + }); + return true; + } + return false; + }, + _updateHash: function () { + var center = this._map.getCenter(), zoom = this._map.getZoom(), bearing = this._map.getBearing(), pitch = this._map.getPitch(), precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2)), hash = '#' + Math.round(zoom * 100) / 100 + '/' + center.lat.toFixed(precision) + '/' + center.lng.toFixed(precision); + if (bearing || pitch) + hash += '/' + Math.round(bearing * 10) / 10; + if (pitch) + hash += '/' + Math.round(pitch); + window.history.replaceState('', '', hash); + } }; - -/** - * Multiplies two mat3's - * - * @param {mat3} out the receiving matrix - * @param {mat3} a the first operand - * @param {mat3} b the second operand - * @returns {mat3} out - */ -mat3.multiply = function (out, a, b) { - var a00 = a[0], a01 = a[1], a02 = a[2], - a10 = a[3], a11 = a[4], a12 = a[5], - a20 = a[6], a21 = a[7], a22 = a[8], - - b00 = b[0], b01 = b[1], b02 = b[2], - b10 = b[3], b11 = b[4], b12 = b[5], - b20 = b[6], b21 = b[7], b22 = b[8]; - - out[0] = b00 * a00 + b01 * a10 + b02 * a20; - out[1] = b00 * a01 + b01 * a11 + b02 * a21; - out[2] = b00 * a02 + b01 * a12 + b02 * a22; - - out[3] = b10 * a00 + b11 * a10 + b12 * a20; - out[4] = b10 * a01 + b11 * a11 + b12 * a21; - out[5] = b10 * a02 + b11 * a12 + b12 * a22; - - out[6] = b20 * a00 + b21 * a10 + b22 * a20; - out[7] = b20 * a01 + b21 * a11 + b22 * a21; - out[8] = b20 * a02 + b21 * a12 + b22 * a22; - return out; +},{"../util/util":188,"../util/window":173}],166:[function(require,module,exports){ +'use strict'; +var util = require('../util/util'); +var browser = require('../util/browser'); +var window = require('../util/window'); +var Evented = require('../util/evented'); +var DOM = require('../util/dom'); +var Style = require('../style/style'); +var AnimationLoop = require('../style/animation_loop'); +var Painter = require('../render/painter'); +var Transform = require('../geo/transform'); +var Hash = require('./hash'); +var bindHandlers = require('./bind_handlers'); +var Camera = require('./camera'); +var LngLat = require('../geo/lng_lat'); +var LngLatBounds = require('../geo/lng_lat_bounds'); +var Point = require('point-geometry'); +var Attribution = require('./control/attribution'); +var isSupported = require('mapbox-gl-supported'); +var defaultMinZoom = 0; +var defaultMaxZoom = 20; +var defaultOptions = { + center: [ + 0, + 0 + ], + zoom: 0, + bearing: 0, + pitch: 0, + minZoom: defaultMinZoom, + maxZoom: defaultMaxZoom, + interactive: true, + scrollZoom: true, + boxZoom: true, + dragRotate: true, + dragPan: true, + keyboard: true, + doubleClickZoom: true, + touchZoomRotate: true, + bearingSnap: 7, + hash: false, + attributionControl: true, + failIfMajorPerformanceCaveat: false, + preserveDrawingBuffer: false, + trackResize: true +}; +var Map = module.exports = function (options) { + options = util.extend({}, defaultOptions, options); + this._interactive = options.interactive; + this._failIfMajorPerformanceCaveat = options.failIfMajorPerformanceCaveat; + this._preserveDrawingBuffer = options.preserveDrawingBuffer; + this._trackResize = options.trackResize; + this._bearingSnap = options.bearingSnap; + if (typeof options.container === 'string') { + this._container = window.document.getElementById(options.container); + } else { + this._container = options.container; + } + this.animationLoop = new AnimationLoop(); + this.transform = new Transform(options.minZoom, options.maxZoom); + if (options.maxBounds) { + this.setMaxBounds(options.maxBounds); + } + util.bindAll([ + '_onWindowOnline', + '_onWindowResize', + '_contextLost', + '_contextRestored', + '_update', + '_render' + ], this); + this._setupContainer(); + this._setupPainter(); + this.on('move', this._update.bind(this, false)); + this.on('zoom', this._update.bind(this, true)); + this.on('moveend', function () { + this.animationLoop.set(300); + this._rerender(); + }.bind(this)); + if (typeof window !== 'undefined') { + window.addEventListener('online', this._onWindowOnline, false); + window.addEventListener('resize', this._onWindowResize, false); + } + bindHandlers(this, options); + this._hash = options.hash && new Hash().addTo(this); + if (!this._hash || !this._hash._onHashChange()) { + this.jumpTo({ + center: options.center, + zoom: options.zoom, + bearing: options.bearing, + pitch: options.pitch + }); + } + this._classes = []; + this.resize(); + if (options.classes) + this.setClasses(options.classes); + if (options.style) + this.setStyle(options.style); + if (options.attributionControl) + this.addControl(new Attribution(options.attributionControl)); + this.on('style.load', function () { + if (this.transform.unmodified) { + this.jumpTo(this.style.stylesheet); + } + this.style.update(this._classes, { transition: false }); + }); + this.on('data', function (event) { + if (event.dataType === 'style') { + this._update(true); + } else { + this._update(); + } + }); }; - -/** - * Alias for {@link mat3.multiply} - * @function - */ -mat3.mul = mat3.multiply; - -/** - * Translate a mat3 by the given vector - * - * @param {mat3} out the receiving matrix - * @param {mat3} a the matrix to translate - * @param {vec2} v vector to translate by - * @returns {mat3} out - */ -mat3.translate = function(out, a, v) { - var a00 = a[0], a01 = a[1], a02 = a[2], - a10 = a[3], a11 = a[4], a12 = a[5], - a20 = a[6], a21 = a[7], a22 = a[8], - x = v[0], y = v[1]; - - out[0] = a00; - out[1] = a01; - out[2] = a02; - - out[3] = a10; - out[4] = a11; - out[5] = a12; - - out[6] = x * a00 + y * a10 + a20; - out[7] = x * a01 + y * a11 + a21; - out[8] = x * a02 + y * a12 + a22; - return out; -}; - -/** - * Rotates a mat3 by the given angle - * - * @param {mat3} out the receiving matrix - * @param {mat3} a the matrix to rotate - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat3} out - */ -mat3.rotate = function (out, a, rad) { - var a00 = a[0], a01 = a[1], a02 = a[2], - a10 = a[3], a11 = a[4], a12 = a[5], - a20 = a[6], a21 = a[7], a22 = a[8], - - s = Math.sin(rad), - c = Math.cos(rad); - - out[0] = c * a00 + s * a10; - out[1] = c * a01 + s * a11; - out[2] = c * a02 + s * a12; - - out[3] = c * a10 - s * a00; - out[4] = c * a11 - s * a01; - out[5] = c * a12 - s * a02; - - out[6] = a20; - out[7] = a21; - out[8] = a22; - return out; -}; - -/** - * Scales the mat3 by the dimensions in the given vec2 - * - * @param {mat3} out the receiving matrix - * @param {mat3} a the matrix to rotate - * @param {vec2} v the vec2 to scale the matrix by - * @returns {mat3} out - **/ -mat3.scale = function(out, a, v) { - var x = v[0], y = v[1]; - - out[0] = x * a[0]; - out[1] = x * a[1]; - out[2] = x * a[2]; - - out[3] = y * a[3]; - out[4] = y * a[4]; - out[5] = y * a[5]; - - out[6] = a[6]; - out[7] = a[7]; - out[8] = a[8]; - return out; -}; - -/** - * Creates a matrix from a vector translation - * This is equivalent to (but much faster than): - * - * mat3.identity(dest); - * mat3.translate(dest, dest, vec); - * - * @param {mat3} out mat3 receiving operation result - * @param {vec2} v Translation vector - * @returns {mat3} out - */ -mat3.fromTranslation = function(out, v) { - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 1; - out[5] = 0; - out[6] = v[0]; - out[7] = v[1]; - out[8] = 1; - return out; -} - -/** - * Creates a matrix from a given angle - * This is equivalent to (but much faster than): - * - * mat3.identity(dest); - * mat3.rotate(dest, dest, rad); - * - * @param {mat3} out mat3 receiving operation result - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat3} out - */ -mat3.fromRotation = function(out, rad) { - var s = Math.sin(rad), c = Math.cos(rad); - - out[0] = c; - out[1] = s; - out[2] = 0; - - out[3] = -s; - out[4] = c; - out[5] = 0; - - out[6] = 0; - out[7] = 0; - out[8] = 1; - return out; -} - -/** - * Creates a matrix from a vector scaling - * This is equivalent to (but much faster than): - * - * mat3.identity(dest); - * mat3.scale(dest, dest, vec); - * - * @param {mat3} out mat3 receiving operation result - * @param {vec2} v Scaling vector - * @returns {mat3} out - */ -mat3.fromScaling = function(out, v) { - out[0] = v[0]; - out[1] = 0; - out[2] = 0; - - out[3] = 0; - out[4] = v[1]; - out[5] = 0; - - out[6] = 0; - out[7] = 0; - out[8] = 1; - return out; -} - -/** - * Copies the values from a mat2d into a mat3 - * - * @param {mat3} out the receiving matrix - * @param {mat2d} a the matrix to copy - * @returns {mat3} out - **/ -mat3.fromMat2d = function(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = 0; - - out[3] = a[2]; - out[4] = a[3]; - out[5] = 0; - - out[6] = a[4]; - out[7] = a[5]; - out[8] = 1; - return out; -}; - -/** -* Calculates a 3x3 matrix from the given quaternion -* -* @param {mat3} out mat3 receiving operation result -* @param {quat} q Quaternion to create matrix from -* -* @returns {mat3} out -*/ -mat3.fromQuat = function (out, q) { - var x = q[0], y = q[1], z = q[2], w = q[3], - x2 = x + x, - y2 = y + y, - z2 = z + z, - - xx = x * x2, - yx = y * x2, - yy = y * y2, - zx = z * x2, - zy = z * y2, - zz = z * z2, - wx = w * x2, - wy = w * y2, - wz = w * z2; - - out[0] = 1 - yy - zz; - out[3] = yx - wz; - out[6] = zx + wy; - - out[1] = yx + wz; - out[4] = 1 - xx - zz; - out[7] = zy - wx; - - out[2] = zx - wy; - out[5] = zy + wx; - out[8] = 1 - xx - yy; - - return out; -}; - -/** -* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix -* -* @param {mat3} out mat3 receiving operation result -* @param {mat4} a Mat4 to derive the normal matrix from -* -* @returns {mat3} out -*/ -mat3.normalFromMat4 = function (out, a) { - var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], - a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], - a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], - a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], - - b00 = a00 * a11 - a01 * a10, - b01 = a00 * a12 - a02 * a10, - b02 = a00 * a13 - a03 * a10, - b03 = a01 * a12 - a02 * a11, - b04 = a01 * a13 - a03 * a11, - b05 = a02 * a13 - a03 * a12, - b06 = a20 * a31 - a21 * a30, - b07 = a20 * a32 - a22 * a30, - b08 = a20 * a33 - a23 * a30, - b09 = a21 * a32 - a22 * a31, - b10 = a21 * a33 - a23 * a31, - b11 = a22 * a33 - a23 * a32, - - // Calculate the determinant - det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; - - if (!det) { - return null; - } - det = 1.0 / det; - - out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; - out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det; - out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det; - - out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det; - out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det; - out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det; - - out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det; - out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det; - out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det; - - return out; -}; - -/** - * Returns a string representation of a mat3 - * - * @param {mat3} mat matrix to represent as a string - * @returns {String} string representation of the matrix - */ -mat3.str = function (a) { - return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + - a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + - a[6] + ', ' + a[7] + ', ' + a[8] + ')'; -}; - -/** - * Returns Frobenius norm of a mat3 - * - * @param {mat3} a the matrix to calculate Frobenius norm of - * @returns {Number} Frobenius norm - */ -mat3.frob = function (a) { - return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2))) -}; - - -module.exports = mat3; - -},{"./common.js":124}],128:[function(require,module,exports){ -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -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. */ - -var glMatrix = require("./common.js"); - -/** - * @class 4x4 Matrix - * @name mat4 - */ -var mat4 = {}; - -/** - * Creates a new identity mat4 - * - * @returns {mat4} a new 4x4 matrix - */ -mat4.create = function() { - var out = new glMatrix.ARRAY_TYPE(16); - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = 1; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = 1; - out[11] = 0; - out[12] = 0; - out[13] = 0; - out[14] = 0; - out[15] = 1; - return out; -}; - -/** - * Creates a new mat4 initialized with values from an existing matrix - * - * @param {mat4} a matrix to clone - * @returns {mat4} a new 4x4 matrix - */ -mat4.clone = function(a) { - var out = new glMatrix.ARRAY_TYPE(16); - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[4] = a[4]; - out[5] = a[5]; - out[6] = a[6]; - out[7] = a[7]; - out[8] = a[8]; - out[9] = a[9]; - out[10] = a[10]; - out[11] = a[11]; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - return out; -}; - -/** - * Copy the values from one mat4 to another - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the source matrix - * @returns {mat4} out - */ -mat4.copy = function(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[4] = a[4]; - out[5] = a[5]; - out[6] = a[6]; - out[7] = a[7]; - out[8] = a[8]; - out[9] = a[9]; - out[10] = a[10]; - out[11] = a[11]; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - return out; -}; - -/** - * Set a mat4 to the identity matrix - * - * @param {mat4} out the receiving matrix - * @returns {mat4} out - */ -mat4.identity = function(out) { - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = 1; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = 1; - out[11] = 0; - out[12] = 0; - out[13] = 0; - out[14] = 0; - out[15] = 1; - return out; -}; - -/** - * Transpose the values of a mat4 - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the source matrix - * @returns {mat4} out - */ -mat4.transpose = function(out, a) { - // If we are transposing ourselves we can skip a few steps but have to cache some values - if (out === a) { - var a01 = a[1], a02 = a[2], a03 = a[3], - a12 = a[6], a13 = a[7], - a23 = a[11]; - - out[1] = a[4]; - out[2] = a[8]; - out[3] = a[12]; - out[4] = a01; - out[6] = a[9]; - out[7] = a[13]; - out[8] = a02; - out[9] = a12; - out[11] = a[14]; - out[12] = a03; - out[13] = a13; - out[14] = a23; - } else { - out[0] = a[0]; - out[1] = a[4]; - out[2] = a[8]; - out[3] = a[12]; - out[4] = a[1]; - out[5] = a[5]; - out[6] = a[9]; - out[7] = a[13]; - out[8] = a[2]; - out[9] = a[6]; - out[10] = a[10]; - out[11] = a[14]; - out[12] = a[3]; - out[13] = a[7]; - out[14] = a[11]; - out[15] = a[15]; - } - - return out; -}; - -/** - * Inverts a mat4 - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the source matrix - * @returns {mat4} out - */ -mat4.invert = function(out, a) { - var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], - a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], - a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], - a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], - - b00 = a00 * a11 - a01 * a10, - b01 = a00 * a12 - a02 * a10, - b02 = a00 * a13 - a03 * a10, - b03 = a01 * a12 - a02 * a11, - b04 = a01 * a13 - a03 * a11, - b05 = a02 * a13 - a03 * a12, - b06 = a20 * a31 - a21 * a30, - b07 = a20 * a32 - a22 * a30, - b08 = a20 * a33 - a23 * a30, - b09 = a21 * a32 - a22 * a31, - b10 = a21 * a33 - a23 * a31, - b11 = a22 * a33 - a23 * a32, - - // Calculate the determinant - det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; - - if (!det) { - return null; - } - det = 1.0 / det; - - out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; - out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; - out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; - out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; - out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; - out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; - out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; - out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; - out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; - out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; - out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; - out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; - out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; - out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; - out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; - out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; - - return out; -}; - -/** - * Calculates the adjugate of a mat4 - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the source matrix - * @returns {mat4} out - */ -mat4.adjoint = function(out, a) { - var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], - a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], - a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], - a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; - - out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22)); - out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22)); - out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12)); - out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12)); - out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22)); - out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22)); - out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12)); - out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12)); - out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21)); - out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21)); - out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11)); - out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11)); - out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21)); - out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21)); - out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11)); - out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11)); - return out; -}; - -/** - * Calculates the determinant of a mat4 - * - * @param {mat4} a the source matrix - * @returns {Number} determinant of a - */ -mat4.determinant = function (a) { - var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], - a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], - a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], - a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], - - b00 = a00 * a11 - a01 * a10, - b01 = a00 * a12 - a02 * a10, - b02 = a00 * a13 - a03 * a10, - b03 = a01 * a12 - a02 * a11, - b04 = a01 * a13 - a03 * a11, - b05 = a02 * a13 - a03 * a12, - b06 = a20 * a31 - a21 * a30, - b07 = a20 * a32 - a22 * a30, - b08 = a20 * a33 - a23 * a30, - b09 = a21 * a32 - a22 * a31, - b10 = a21 * a33 - a23 * a31, - b11 = a22 * a33 - a23 * a32; - - // Calculate the determinant - return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; -}; - -/** - * Multiplies two mat4's - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the first operand - * @param {mat4} b the second operand - * @returns {mat4} out - */ -mat4.multiply = function (out, a, b) { - var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], - a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], - a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], - a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; - - // Cache only the current line of the second matrix - var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; - out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - - b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; - out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - - b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; - out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - - b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; - out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - return out; -}; - -/** - * Alias for {@link mat4.multiply} - * @function - */ -mat4.mul = mat4.multiply; - -/** - * Translate a mat4 by the given vector - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the matrix to translate - * @param {vec3} v vector to translate by - * @returns {mat4} out - */ -mat4.translate = function (out, a, v) { - var x = v[0], y = v[1], z = v[2], - a00, a01, a02, a03, - a10, a11, a12, a13, - a20, a21, a22, a23; - - if (a === out) { - out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; - out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; - out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; - out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; - } else { - a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; - a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; - a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; - - out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03; - out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13; - out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23; - - out[12] = a00 * x + a10 * y + a20 * z + a[12]; - out[13] = a01 * x + a11 * y + a21 * z + a[13]; - out[14] = a02 * x + a12 * y + a22 * z + a[14]; - out[15] = a03 * x + a13 * y + a23 * z + a[15]; - } - - return out; -}; - -/** - * Scales the mat4 by the dimensions in the given vec3 - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the matrix to scale - * @param {vec3} v the vec3 to scale the matrix by - * @returns {mat4} out - **/ -mat4.scale = function(out, a, v) { - var x = v[0], y = v[1], z = v[2]; - - out[0] = a[0] * x; - out[1] = a[1] * x; - out[2] = a[2] * x; - out[3] = a[3] * x; - out[4] = a[4] * y; - out[5] = a[5] * y; - out[6] = a[6] * y; - out[7] = a[7] * y; - out[8] = a[8] * z; - out[9] = a[9] * z; - out[10] = a[10] * z; - out[11] = a[11] * z; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - return out; -}; - -/** - * Rotates a mat4 by the given angle around the given axis - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the matrix to rotate - * @param {Number} rad the angle to rotate the matrix by - * @param {vec3} axis the axis to rotate around - * @returns {mat4} out - */ -mat4.rotate = function (out, a, rad, axis) { - var x = axis[0], y = axis[1], z = axis[2], - len = Math.sqrt(x * x + y * y + z * z), - s, c, t, - a00, a01, a02, a03, - a10, a11, a12, a13, - a20, a21, a22, a23, - b00, b01, b02, - b10, b11, b12, - b20, b21, b22; - - if (Math.abs(len) < glMatrix.EPSILON) { return null; } - - len = 1 / len; - x *= len; - y *= len; - z *= len; - - s = Math.sin(rad); - c = Math.cos(rad); - t = 1 - c; - - a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; - a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; - a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; - - // Construct the elements of the rotation matrix - b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s; - b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s; - b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c; - - // Perform rotation-specific matrix multiplication - out[0] = a00 * b00 + a10 * b01 + a20 * b02; - out[1] = a01 * b00 + a11 * b01 + a21 * b02; - out[2] = a02 * b00 + a12 * b01 + a22 * b02; - out[3] = a03 * b00 + a13 * b01 + a23 * b02; - out[4] = a00 * b10 + a10 * b11 + a20 * b12; - out[5] = a01 * b10 + a11 * b11 + a21 * b12; - out[6] = a02 * b10 + a12 * b11 + a22 * b12; - out[7] = a03 * b10 + a13 * b11 + a23 * b12; - out[8] = a00 * b20 + a10 * b21 + a20 * b22; - out[9] = a01 * b20 + a11 * b21 + a21 * b22; - out[10] = a02 * b20 + a12 * b21 + a22 * b22; - out[11] = a03 * b20 + a13 * b21 + a23 * b22; - - if (a !== out) { // If the source and destination differ, copy the unchanged last row - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - } - return out; -}; - -/** - * Rotates a matrix by the given angle around the X axis - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the matrix to rotate - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat4} out - */ -mat4.rotateX = function (out, a, rad) { - var s = Math.sin(rad), - c = Math.cos(rad), - a10 = a[4], - a11 = a[5], - a12 = a[6], - a13 = a[7], - a20 = a[8], - a21 = a[9], - a22 = a[10], - a23 = a[11]; - - if (a !== out) { // If the source and destination differ, copy the unchanged rows - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - } - - // Perform axis-specific matrix multiplication - out[4] = a10 * c + a20 * s; - out[5] = a11 * c + a21 * s; - out[6] = a12 * c + a22 * s; - out[7] = a13 * c + a23 * s; - out[8] = a20 * c - a10 * s; - out[9] = a21 * c - a11 * s; - out[10] = a22 * c - a12 * s; - out[11] = a23 * c - a13 * s; - return out; -}; - -/** - * Rotates a matrix by the given angle around the Y axis - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the matrix to rotate - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat4} out - */ -mat4.rotateY = function (out, a, rad) { - var s = Math.sin(rad), - c = Math.cos(rad), - a00 = a[0], - a01 = a[1], - a02 = a[2], - a03 = a[3], - a20 = a[8], - a21 = a[9], - a22 = a[10], - a23 = a[11]; - - if (a !== out) { // If the source and destination differ, copy the unchanged rows - out[4] = a[4]; - out[5] = a[5]; - out[6] = a[6]; - out[7] = a[7]; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - } - - // Perform axis-specific matrix multiplication - out[0] = a00 * c - a20 * s; - out[1] = a01 * c - a21 * s; - out[2] = a02 * c - a22 * s; - out[3] = a03 * c - a23 * s; - out[8] = a00 * s + a20 * c; - out[9] = a01 * s + a21 * c; - out[10] = a02 * s + a22 * c; - out[11] = a03 * s + a23 * c; - return out; -}; - -/** - * Rotates a matrix by the given angle around the Z axis - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the matrix to rotate - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat4} out - */ -mat4.rotateZ = function (out, a, rad) { - var s = Math.sin(rad), - c = Math.cos(rad), - a00 = a[0], - a01 = a[1], - a02 = a[2], - a03 = a[3], - a10 = a[4], - a11 = a[5], - a12 = a[6], - a13 = a[7]; - - if (a !== out) { // If the source and destination differ, copy the unchanged last row - out[8] = a[8]; - out[9] = a[9]; - out[10] = a[10]; - out[11] = a[11]; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - } - - // Perform axis-specific matrix multiplication - out[0] = a00 * c + a10 * s; - out[1] = a01 * c + a11 * s; - out[2] = a02 * c + a12 * s; - out[3] = a03 * c + a13 * s; - out[4] = a10 * c - a00 * s; - out[5] = a11 * c - a01 * s; - out[6] = a12 * c - a02 * s; - out[7] = a13 * c - a03 * s; - return out; -}; - -/** - * Creates a matrix from a vector translation - * This is equivalent to (but much faster than): - * - * mat4.identity(dest); - * mat4.translate(dest, dest, vec); - * - * @param {mat4} out mat4 receiving operation result - * @param {vec3} v Translation vector - * @returns {mat4} out - */ -mat4.fromTranslation = function(out, v) { - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = 1; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = 1; - out[11] = 0; - out[12] = v[0]; - out[13] = v[1]; - out[14] = v[2]; - out[15] = 1; - return out; -} - -/** - * Creates a matrix from a vector scaling - * This is equivalent to (but much faster than): - * - * mat4.identity(dest); - * mat4.scale(dest, dest, vec); - * - * @param {mat4} out mat4 receiving operation result - * @param {vec3} v Scaling vector - * @returns {mat4} out - */ -mat4.fromScaling = function(out, v) { - out[0] = v[0]; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = v[1]; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = v[2]; - out[11] = 0; - out[12] = 0; - out[13] = 0; - out[14] = 0; - out[15] = 1; - return out; -} - -/** - * Creates a matrix from a given angle around a given axis - * This is equivalent to (but much faster than): - * - * mat4.identity(dest); - * mat4.rotate(dest, dest, rad, axis); - * - * @param {mat4} out mat4 receiving operation result - * @param {Number} rad the angle to rotate the matrix by - * @param {vec3} axis the axis to rotate around - * @returns {mat4} out - */ -mat4.fromRotation = function(out, rad, axis) { - var x = axis[0], y = axis[1], z = axis[2], - len = Math.sqrt(x * x + y * y + z * z), - s, c, t; - - if (Math.abs(len) < glMatrix.EPSILON) { return null; } - - len = 1 / len; - x *= len; - y *= len; - z *= len; - - s = Math.sin(rad); - c = Math.cos(rad); - t = 1 - c; - - // Perform rotation-specific matrix multiplication - out[0] = x * x * t + c; - out[1] = y * x * t + z * s; - out[2] = z * x * t - y * s; - out[3] = 0; - out[4] = x * y * t - z * s; - out[5] = y * y * t + c; - out[6] = z * y * t + x * s; - out[7] = 0; - out[8] = x * z * t + y * s; - out[9] = y * z * t - x * s; - out[10] = z * z * t + c; - out[11] = 0; - out[12] = 0; - out[13] = 0; - out[14] = 0; - out[15] = 1; - return out; -} - -/** - * Creates a matrix from the given angle around the X axis - * This is equivalent to (but much faster than): - * - * mat4.identity(dest); - * mat4.rotateX(dest, dest, rad); - * - * @param {mat4} out mat4 receiving operation result - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat4} out - */ -mat4.fromXRotation = function(out, rad) { - var s = Math.sin(rad), - c = Math.cos(rad); - - // Perform axis-specific matrix multiplication - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = c; - out[6] = s; - out[7] = 0; - out[8] = 0; - out[9] = -s; - out[10] = c; - out[11] = 0; - out[12] = 0; - out[13] = 0; - out[14] = 0; - out[15] = 1; - return out; -} - -/** - * Creates a matrix from the given angle around the Y axis - * This is equivalent to (but much faster than): - * - * mat4.identity(dest); - * mat4.rotateY(dest, dest, rad); - * - * @param {mat4} out mat4 receiving operation result - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat4} out - */ -mat4.fromYRotation = function(out, rad) { - var s = Math.sin(rad), - c = Math.cos(rad); - - // Perform axis-specific matrix multiplication - out[0] = c; - out[1] = 0; - out[2] = -s; - out[3] = 0; - out[4] = 0; - out[5] = 1; - out[6] = 0; - out[7] = 0; - out[8] = s; - out[9] = 0; - out[10] = c; - out[11] = 0; - out[12] = 0; - out[13] = 0; - out[14] = 0; - out[15] = 1; - return out; -} - -/** - * Creates a matrix from the given angle around the Z axis - * This is equivalent to (but much faster than): - * - * mat4.identity(dest); - * mat4.rotateZ(dest, dest, rad); - * - * @param {mat4} out mat4 receiving operation result - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat4} out - */ -mat4.fromZRotation = function(out, rad) { - var s = Math.sin(rad), - c = Math.cos(rad); - - // Perform axis-specific matrix multiplication - out[0] = c; - out[1] = s; - out[2] = 0; - out[3] = 0; - out[4] = -s; - out[5] = c; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = 1; - out[11] = 0; - out[12] = 0; - out[13] = 0; - out[14] = 0; - out[15] = 1; - return out; -} - -/** - * Creates a matrix from a quaternion rotation and vector translation - * This is equivalent to (but much faster than): - * - * mat4.identity(dest); - * mat4.translate(dest, vec); - * var quatMat = mat4.create(); - * quat4.toMat4(quat, quatMat); - * mat4.multiply(dest, quatMat); - * - * @param {mat4} out mat4 receiving operation result - * @param {quat4} q Rotation quaternion - * @param {vec3} v Translation vector - * @returns {mat4} out - */ -mat4.fromRotationTranslation = function (out, q, v) { - // Quaternion math - var x = q[0], y = q[1], z = q[2], w = q[3], - x2 = x + x, - y2 = y + y, - z2 = z + z, - - xx = x * x2, - xy = x * y2, - xz = x * z2, - yy = y * y2, - yz = y * z2, - zz = z * z2, - wx = w * x2, - wy = w * y2, - wz = w * z2; - - out[0] = 1 - (yy + zz); - out[1] = xy + wz; - out[2] = xz - wy; - out[3] = 0; - out[4] = xy - wz; - out[5] = 1 - (xx + zz); - out[6] = yz + wx; - out[7] = 0; - out[8] = xz + wy; - out[9] = yz - wx; - out[10] = 1 - (xx + yy); - out[11] = 0; - out[12] = v[0]; - out[13] = v[1]; - out[14] = v[2]; - out[15] = 1; - - return out; -}; - -/** - * Creates a matrix from a quaternion rotation, vector translation and vector scale - * This is equivalent to (but much faster than): - * - * mat4.identity(dest); - * mat4.translate(dest, vec); - * var quatMat = mat4.create(); - * quat4.toMat4(quat, quatMat); - * mat4.multiply(dest, quatMat); - * mat4.scale(dest, scale) - * - * @param {mat4} out mat4 receiving operation result - * @param {quat4} q Rotation quaternion - * @param {vec3} v Translation vector - * @param {vec3} s Scaling vector - * @returns {mat4} out - */ -mat4.fromRotationTranslationScale = function (out, q, v, s) { - // Quaternion math - var x = q[0], y = q[1], z = q[2], w = q[3], - x2 = x + x, - y2 = y + y, - z2 = z + z, - - xx = x * x2, - xy = x * y2, - xz = x * z2, - yy = y * y2, - yz = y * z2, - zz = z * z2, - wx = w * x2, - wy = w * y2, - wz = w * z2, - sx = s[0], - sy = s[1], - sz = s[2]; - - out[0] = (1 - (yy + zz)) * sx; - out[1] = (xy + wz) * sx; - out[2] = (xz - wy) * sx; - out[3] = 0; - out[4] = (xy - wz) * sy; - out[5] = (1 - (xx + zz)) * sy; - out[6] = (yz + wx) * sy; - out[7] = 0; - out[8] = (xz + wy) * sz; - out[9] = (yz - wx) * sz; - out[10] = (1 - (xx + yy)) * sz; - out[11] = 0; - out[12] = v[0]; - out[13] = v[1]; - out[14] = v[2]; - out[15] = 1; - - return out; -}; - -/** - * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin - * This is equivalent to (but much faster than): - * - * mat4.identity(dest); - * mat4.translate(dest, vec); - * mat4.translate(dest, origin); - * var quatMat = mat4.create(); - * quat4.toMat4(quat, quatMat); - * mat4.multiply(dest, quatMat); - * mat4.scale(dest, scale) - * mat4.translate(dest, negativeOrigin); - * - * @param {mat4} out mat4 receiving operation result - * @param {quat4} q Rotation quaternion - * @param {vec3} v Translation vector - * @param {vec3} s Scaling vector - * @param {vec3} o The origin vector around which to scale and rotate - * @returns {mat4} out - */ -mat4.fromRotationTranslationScaleOrigin = function (out, q, v, s, o) { - // Quaternion math - var x = q[0], y = q[1], z = q[2], w = q[3], - x2 = x + x, - y2 = y + y, - z2 = z + z, - - xx = x * x2, - xy = x * y2, - xz = x * z2, - yy = y * y2, - yz = y * z2, - zz = z * z2, - wx = w * x2, - wy = w * y2, - wz = w * z2, - - sx = s[0], - sy = s[1], - sz = s[2], - - ox = o[0], - oy = o[1], - oz = o[2]; - - out[0] = (1 - (yy + zz)) * sx; - out[1] = (xy + wz) * sx; - out[2] = (xz - wy) * sx; - out[3] = 0; - out[4] = (xy - wz) * sy; - out[5] = (1 - (xx + zz)) * sy; - out[6] = (yz + wx) * sy; - out[7] = 0; - out[8] = (xz + wy) * sz; - out[9] = (yz - wx) * sz; - out[10] = (1 - (xx + yy)) * sz; - out[11] = 0; - out[12] = v[0] + ox - (out[0] * ox + out[4] * oy + out[8] * oz); - out[13] = v[1] + oy - (out[1] * ox + out[5] * oy + out[9] * oz); - out[14] = v[2] + oz - (out[2] * ox + out[6] * oy + out[10] * oz); - out[15] = 1; - - return out; -}; - -mat4.fromQuat = function (out, q) { - var x = q[0], y = q[1], z = q[2], w = q[3], - x2 = x + x, - y2 = y + y, - z2 = z + z, - - xx = x * x2, - yx = y * x2, - yy = y * y2, - zx = z * x2, - zy = z * y2, - zz = z * z2, - wx = w * x2, - wy = w * y2, - wz = w * z2; - - out[0] = 1 - yy - zz; - out[1] = yx + wz; - out[2] = zx - wy; - out[3] = 0; - - out[4] = yx - wz; - out[5] = 1 - xx - zz; - out[6] = zy + wx; - out[7] = 0; - - out[8] = zx + wy; - out[9] = zy - wx; - out[10] = 1 - xx - yy; - out[11] = 0; - - out[12] = 0; - out[13] = 0; - out[14] = 0; - out[15] = 1; - - return out; -}; - -/** - * Generates a frustum matrix with the given bounds - * - * @param {mat4} out mat4 frustum matrix will be written into - * @param {Number} left Left bound of the frustum - * @param {Number} right Right bound of the frustum - * @param {Number} bottom Bottom bound of the frustum - * @param {Number} top Top bound of the frustum - * @param {Number} near Near bound of the frustum - * @param {Number} far Far bound of the frustum - * @returns {mat4} out - */ -mat4.frustum = function (out, left, right, bottom, top, near, far) { - var rl = 1 / (right - left), - tb = 1 / (top - bottom), - nf = 1 / (near - far); - out[0] = (near * 2) * rl; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = (near * 2) * tb; - out[6] = 0; - out[7] = 0; - out[8] = (right + left) * rl; - out[9] = (top + bottom) * tb; - out[10] = (far + near) * nf; - out[11] = -1; - out[12] = 0; - out[13] = 0; - out[14] = (far * near * 2) * nf; - out[15] = 0; - return out; -}; - -/** - * Generates a perspective projection matrix with the given bounds - * - * @param {mat4} out mat4 frustum matrix will be written into - * @param {number} fovy Vertical field of view in radians - * @param {number} aspect Aspect ratio. typically viewport width/height - * @param {number} near Near bound of the frustum - * @param {number} far Far bound of the frustum - * @returns {mat4} out - */ -mat4.perspective = function (out, fovy, aspect, near, far) { - var f = 1.0 / Math.tan(fovy / 2), - nf = 1 / (near - far); - out[0] = f / aspect; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = f; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = (far + near) * nf; - out[11] = -1; - out[12] = 0; - out[13] = 0; - out[14] = (2 * far * near) * nf; - out[15] = 0; - return out; -}; - -/** - * Generates a perspective projection matrix with the given field of view. - * This is primarily useful for generating projection matrices to be used - * with the still experiemental WebVR API. - * - * @param {mat4} out mat4 frustum matrix will be written into - * @param {number} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees - * @param {number} near Near bound of the frustum - * @param {number} far Far bound of the frustum - * @returns {mat4} out - */ -mat4.perspectiveFromFieldOfView = function (out, fov, near, far) { - var upTan = Math.tan(fov.upDegrees * Math.PI/180.0), - downTan = Math.tan(fov.downDegrees * Math.PI/180.0), - leftTan = Math.tan(fov.leftDegrees * Math.PI/180.0), - rightTan = Math.tan(fov.rightDegrees * Math.PI/180.0), - xScale = 2.0 / (leftTan + rightTan), - yScale = 2.0 / (upTan + downTan); - - out[0] = xScale; - out[1] = 0.0; - out[2] = 0.0; - out[3] = 0.0; - out[4] = 0.0; - out[5] = yScale; - out[6] = 0.0; - out[7] = 0.0; - out[8] = -((leftTan - rightTan) * xScale * 0.5); - out[9] = ((upTan - downTan) * yScale * 0.5); - out[10] = far / (near - far); - out[11] = -1.0; - out[12] = 0.0; - out[13] = 0.0; - out[14] = (far * near) / (near - far); - out[15] = 0.0; - return out; -} - -/** - * Generates a orthogonal projection matrix with the given bounds - * - * @param {mat4} out mat4 frustum matrix will be written into - * @param {number} left Left bound of the frustum - * @param {number} right Right bound of the frustum - * @param {number} bottom Bottom bound of the frustum - * @param {number} top Top bound of the frustum - * @param {number} near Near bound of the frustum - * @param {number} far Far bound of the frustum - * @returns {mat4} out - */ -mat4.ortho = function (out, left, right, bottom, top, near, far) { - var lr = 1 / (left - right), - bt = 1 / (bottom - top), - nf = 1 / (near - far); - out[0] = -2 * lr; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = -2 * bt; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = 2 * nf; - out[11] = 0; - out[12] = (left + right) * lr; - out[13] = (top + bottom) * bt; - out[14] = (far + near) * nf; - out[15] = 1; - return out; -}; - -/** - * Generates a look-at matrix with the given eye position, focal point, and up axis - * - * @param {mat4} out mat4 frustum matrix will be written into - * @param {vec3} eye Position of the viewer - * @param {vec3} center Point the viewer is looking at - * @param {vec3} up vec3 pointing up - * @returns {mat4} out - */ -mat4.lookAt = function (out, eye, center, up) { - var x0, x1, x2, y0, y1, y2, z0, z1, z2, len, - eyex = eye[0], - eyey = eye[1], - eyez = eye[2], - upx = up[0], - upy = up[1], - upz = up[2], - centerx = center[0], - centery = center[1], - centerz = center[2]; - - if (Math.abs(eyex - centerx) < glMatrix.EPSILON && - Math.abs(eyey - centery) < glMatrix.EPSILON && - Math.abs(eyez - centerz) < glMatrix.EPSILON) { - return mat4.identity(out); - } - - z0 = eyex - centerx; - z1 = eyey - centery; - z2 = eyez - centerz; - - len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); - z0 *= len; - z1 *= len; - z2 *= len; - - x0 = upy * z2 - upz * z1; - x1 = upz * z0 - upx * z2; - x2 = upx * z1 - upy * z0; - len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); - if (!len) { - x0 = 0; - x1 = 0; - x2 = 0; - } else { - len = 1 / len; - x0 *= len; - x1 *= len; - x2 *= len; - } - - y0 = z1 * x2 - z2 * x1; - y1 = z2 * x0 - z0 * x2; - y2 = z0 * x1 - z1 * x0; - - len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); - if (!len) { - y0 = 0; - y1 = 0; - y2 = 0; - } else { - len = 1 / len; - y0 *= len; - y1 *= len; - y2 *= len; - } - - out[0] = x0; - out[1] = y0; - out[2] = z0; - out[3] = 0; - out[4] = x1; - out[5] = y1; - out[6] = z1; - out[7] = 0; - out[8] = x2; - out[9] = y2; - out[10] = z2; - out[11] = 0; - out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); - out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); - out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); - out[15] = 1; - - return out; -}; - -/** - * Returns a string representation of a mat4 - * - * @param {mat4} mat matrix to represent as a string - * @returns {String} string representation of the matrix - */ -mat4.str = function (a) { - return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + - a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + - a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + - a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')'; -}; - -/** - * Returns Frobenius norm of a mat4 - * - * @param {mat4} a the matrix to calculate Frobenius norm of - * @returns {Number} Frobenius norm - */ -mat4.frob = function (a) { - return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2) )) -}; - - -module.exports = mat4; - -},{"./common.js":124}],129:[function(require,module,exports){ -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -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. */ - -var glMatrix = require("./common.js"); -var mat3 = require("./mat3.js"); -var vec3 = require("./vec3.js"); -var vec4 = require("./vec4.js"); - -/** - * @class Quaternion - * @name quat - */ -var quat = {}; - -/** - * Creates a new identity quat - * - * @returns {quat} a new quaternion - */ -quat.create = function() { - var out = new glMatrix.ARRAY_TYPE(4); - out[0] = 0; - out[1] = 0; - out[2] = 0; - out[3] = 1; - return out; -}; - -/** - * Sets a quaternion to represent the shortest rotation from one - * vector to another. - * - * Both vectors are assumed to be unit length. - * - * @param {quat} out the receiving quaternion. - * @param {vec3} a the initial vector - * @param {vec3} b the destination vector - * @returns {quat} out - */ -quat.rotationTo = (function() { - var tmpvec3 = vec3.create(); - var xUnitVec3 = vec3.fromValues(1,0,0); - var yUnitVec3 = vec3.fromValues(0,1,0); - - return function(out, a, b) { - var dot = vec3.dot(a, b); - if (dot < -0.999999) { - vec3.cross(tmpvec3, xUnitVec3, a); - if (vec3.length(tmpvec3) < 0.000001) - vec3.cross(tmpvec3, yUnitVec3, a); - vec3.normalize(tmpvec3, tmpvec3); - quat.setAxisAngle(out, tmpvec3, Math.PI); - return out; - } else if (dot > 0.999999) { - out[0] = 0; - out[1] = 0; - out[2] = 0; - out[3] = 1; - return out; - } else { - vec3.cross(tmpvec3, a, b); - out[0] = tmpvec3[0]; - out[1] = tmpvec3[1]; - out[2] = tmpvec3[2]; - out[3] = 1 + dot; - return quat.normalize(out, out); - } - }; -})(); - -/** - * Sets the specified quaternion with values corresponding to the given - * axes. Each axis is a vec3 and is expected to be unit length and - * perpendicular to all other specified axes. - * - * @param {vec3} view the vector representing the viewing direction - * @param {vec3} right the vector representing the local "right" direction - * @param {vec3} up the vector representing the local "up" direction - * @returns {quat} out - */ -quat.setAxes = (function() { - var matr = mat3.create(); - - return function(out, view, right, up) { - matr[0] = right[0]; - matr[3] = right[1]; - matr[6] = right[2]; - - matr[1] = up[0]; - matr[4] = up[1]; - matr[7] = up[2]; - - matr[2] = -view[0]; - matr[5] = -view[1]; - matr[8] = -view[2]; - - return quat.normalize(out, quat.fromMat3(out, matr)); - }; -})(); - -/** - * Creates a new quat initialized with values from an existing quaternion - * - * @param {quat} a quaternion to clone - * @returns {quat} a new quaternion - * @function - */ -quat.clone = vec4.clone; - -/** - * Creates a new quat initialized with the given values - * - * @param {Number} x X component - * @param {Number} y Y component - * @param {Number} z Z component - * @param {Number} w W component - * @returns {quat} a new quaternion - * @function - */ -quat.fromValues = vec4.fromValues; - -/** - * Copy the values from one quat to another - * - * @param {quat} out the receiving quaternion - * @param {quat} a the source quaternion - * @returns {quat} out - * @function - */ -quat.copy = vec4.copy; - -/** - * Set the components of a quat to the given values - * - * @param {quat} out the receiving quaternion - * @param {Number} x X component - * @param {Number} y Y component - * @param {Number} z Z component - * @param {Number} w W component - * @returns {quat} out - * @function - */ -quat.set = vec4.set; - -/** - * Set a quat to the identity quaternion - * - * @param {quat} out the receiving quaternion - * @returns {quat} out - */ -quat.identity = function(out) { - out[0] = 0; - out[1] = 0; - out[2] = 0; - out[3] = 1; - return out; -}; - -/** - * Sets a quat from the given angle and rotation axis, - * then returns it. - * - * @param {quat} out the receiving quaternion - * @param {vec3} axis the axis around which to rotate - * @param {Number} rad the angle in radians - * @returns {quat} out - **/ -quat.setAxisAngle = function(out, axis, rad) { - rad = rad * 0.5; - var s = Math.sin(rad); - out[0] = s * axis[0]; - out[1] = s * axis[1]; - out[2] = s * axis[2]; - out[3] = Math.cos(rad); - return out; -}; - -/** - * Adds two quat's - * - * @param {quat} out the receiving quaternion - * @param {quat} a the first operand - * @param {quat} b the second operand - * @returns {quat} out - * @function - */ -quat.add = vec4.add; - -/** - * Multiplies two quat's - * - * @param {quat} out the receiving quaternion - * @param {quat} a the first operand - * @param {quat} b the second operand - * @returns {quat} out - */ -quat.multiply = function(out, a, b) { - var ax = a[0], ay = a[1], az = a[2], aw = a[3], - bx = b[0], by = b[1], bz = b[2], bw = b[3]; - - out[0] = ax * bw + aw * bx + ay * bz - az * by; - out[1] = ay * bw + aw * by + az * bx - ax * bz; - out[2] = az * bw + aw * bz + ax * by - ay * bx; - out[3] = aw * bw - ax * bx - ay * by - az * bz; - return out; -}; - -/** - * Alias for {@link quat.multiply} - * @function - */ -quat.mul = quat.multiply; - -/** - * Scales a quat by a scalar number - * - * @param {quat} out the receiving vector - * @param {quat} a the vector to scale - * @param {Number} b amount to scale the vector by - * @returns {quat} out - * @function - */ -quat.scale = vec4.scale; - -/** - * Rotates a quaternion by the given angle about the X axis - * - * @param {quat} out quat receiving operation result - * @param {quat} a quat to rotate - * @param {number} rad angle (in radians) to rotate - * @returns {quat} out - */ -quat.rotateX = function (out, a, rad) { - rad *= 0.5; - - var ax = a[0], ay = a[1], az = a[2], aw = a[3], - bx = Math.sin(rad), bw = Math.cos(rad); - - out[0] = ax * bw + aw * bx; - out[1] = ay * bw + az * bx; - out[2] = az * bw - ay * bx; - out[3] = aw * bw - ax * bx; - return out; -}; - -/** - * Rotates a quaternion by the given angle about the Y axis - * - * @param {quat} out quat receiving operation result - * @param {quat} a quat to rotate - * @param {number} rad angle (in radians) to rotate - * @returns {quat} out - */ -quat.rotateY = function (out, a, rad) { - rad *= 0.5; - - var ax = a[0], ay = a[1], az = a[2], aw = a[3], - by = Math.sin(rad), bw = Math.cos(rad); - - out[0] = ax * bw - az * by; - out[1] = ay * bw + aw * by; - out[2] = az * bw + ax * by; - out[3] = aw * bw - ay * by; - return out; -}; - -/** - * Rotates a quaternion by the given angle about the Z axis - * - * @param {quat} out quat receiving operation result - * @param {quat} a quat to rotate - * @param {number} rad angle (in radians) to rotate - * @returns {quat} out - */ -quat.rotateZ = function (out, a, rad) { - rad *= 0.5; - - var ax = a[0], ay = a[1], az = a[2], aw = a[3], - bz = Math.sin(rad), bw = Math.cos(rad); - - out[0] = ax * bw + ay * bz; - out[1] = ay * bw - ax * bz; - out[2] = az * bw + aw * bz; - out[3] = aw * bw - az * bz; - return out; -}; - -/** - * Calculates the W component of a quat from the X, Y, and Z components. - * Assumes that quaternion is 1 unit in length. - * Any existing W component will be ignored. - * - * @param {quat} out the receiving quaternion - * @param {quat} a quat to calculate W component of - * @returns {quat} out - */ -quat.calculateW = function (out, a) { - var x = a[0], y = a[1], z = a[2]; - - out[0] = x; - out[1] = y; - out[2] = z; - out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); - return out; -}; - -/** - * Calculates the dot product of two quat's - * - * @param {quat} a the first operand - * @param {quat} b the second operand - * @returns {Number} dot product of a and b - * @function - */ -quat.dot = vec4.dot; - -/** - * Performs a linear interpolation between two quat's - * - * @param {quat} out the receiving quaternion - * @param {quat} a the first operand - * @param {quat} b the second operand - * @param {Number} t interpolation amount between the two inputs - * @returns {quat} out - * @function - */ -quat.lerp = vec4.lerp; - -/** - * Performs a spherical linear interpolation between two quat - * - * @param {quat} out the receiving quaternion - * @param {quat} a the first operand - * @param {quat} b the second operand - * @param {Number} t interpolation amount between the two inputs - * @returns {quat} out - */ -quat.slerp = function (out, a, b, t) { - // benchmarks: - // http://jsperf.com/quaternion-slerp-implementations - - var ax = a[0], ay = a[1], az = a[2], aw = a[3], - bx = b[0], by = b[1], bz = b[2], bw = b[3]; - - var omega, cosom, sinom, scale0, scale1; - - // calc cosine - cosom = ax * bx + ay * by + az * bz + aw * bw; - // adjust signs (if necessary) - if ( cosom < 0.0 ) { - cosom = -cosom; - bx = - bx; - by = - by; - bz = - bz; - bw = - bw; +util.extend(Map.prototype, Evented); +util.extend(Map.prototype, Camera.prototype); +util.extend(Map.prototype, { + addControl: function (control) { + control.addTo(this); + return this; + }, + addClass: function (klass, options) { + if (this._classes.indexOf(klass) >= 0 || klass === '') + return this; + this._classes.push(klass); + this._classOptions = options; + if (this.style) + this.style.updateClasses(); + return this._update(true); + }, + removeClass: function (klass, options) { + var i = this._classes.indexOf(klass); + if (i < 0 || klass === '') + return this; + this._classes.splice(i, 1); + this._classOptions = options; + if (this.style) + this.style.updateClasses(); + return this._update(true); + }, + setClasses: function (klasses, options) { + var uniqueClasses = {}; + for (var i = 0; i < klasses.length; i++) { + if (klasses[i] !== '') + uniqueClasses[klasses[i]] = true; + } + this._classes = Object.keys(uniqueClasses); + this._classOptions = options; + if (this.style) + this.style.updateClasses(); + return this._update(true); + }, + hasClass: function (klass) { + return this._classes.indexOf(klass) >= 0; + }, + getClasses: function () { + return this._classes; + }, + resize: function () { + var dimensions = this._containerDimensions(); + var width = dimensions[0]; + var height = dimensions[1]; + this._resizeCanvas(width, height); + this.transform.resize(width, height); + this.painter.resize(width, height); + return this.fire('movestart').fire('move').fire('resize').fire('moveend'); + }, + getBounds: function () { + var bounds = new LngLatBounds(this.transform.pointLocation(new Point(0, this.transform.height)), this.transform.pointLocation(new Point(this.transform.width, 0))); + if (this.transform.angle || this.transform.pitch) { + bounds.extend(this.transform.pointLocation(new Point(this.transform.size.x, 0))); + bounds.extend(this.transform.pointLocation(new Point(0, this.transform.size.y))); + } + return bounds; + }, + setMaxBounds: function (lnglatbounds) { + if (lnglatbounds) { + var b = LngLatBounds.convert(lnglatbounds); + this.transform.lngRange = [ + b.getWest(), + b.getEast() + ]; + this.transform.latRange = [ + b.getSouth(), + b.getNorth() + ]; + this.transform._constrain(); + this._update(); + } else if (lnglatbounds === null || lnglatbounds === undefined) { + this.transform.lngRange = []; + this.transform.latRange = []; + this._update(); + } + return this; + }, + setMinZoom: function (minZoom) { + minZoom = minZoom === null || minZoom === undefined ? defaultMinZoom : minZoom; + if (minZoom >= defaultMinZoom && minZoom <= this.transform.maxZoom) { + this.transform.minZoom = minZoom; + this._update(); + if (this.getZoom() < minZoom) + this.setZoom(minZoom); + return this; + } else + throw new Error('minZoom must be between ' + defaultMinZoom + ' and the current maxZoom, inclusive'); + }, + setMaxZoom: function (maxZoom) { + maxZoom = maxZoom === null || maxZoom === undefined ? defaultMaxZoom : maxZoom; + if (maxZoom >= this.transform.minZoom && maxZoom <= defaultMaxZoom) { + this.transform.maxZoom = maxZoom; + this._update(); + if (this.getZoom() > maxZoom) + this.setZoom(maxZoom); + return this; + } else + throw new Error('maxZoom must be between the current minZoom and ' + defaultMaxZoom + ', inclusive'); + }, + project: function (lnglat) { + return this.transform.locationPoint(LngLat.convert(lnglat)); + }, + unproject: function (point) { + return this.transform.pointLocation(Point.convert(point)); + }, + queryRenderedFeatures: function () { + var params = {}; + var geometry; + if (arguments.length === 2) { + geometry = arguments[0]; + params = arguments[1]; + } else if (arguments.length === 1 && isPointLike(arguments[0])) { + geometry = arguments[0]; + } else if (arguments.length === 1) { + params = arguments[0]; + } + return this.style.queryRenderedFeatures(this._makeQueryGeometry(geometry), params, this.transform.zoom, this.transform.angle); + function isPointLike(input) { + return input instanceof Point || Array.isArray(input); + } + }, + _makeQueryGeometry: function (pointOrBox) { + if (pointOrBox === undefined) { + pointOrBox = [ + Point.convert([ + 0, + 0 + ]), + Point.convert([ + this.transform.width, + this.transform.height + ]) + ]; + } + var queryGeometry; + var isPoint = pointOrBox instanceof Point || typeof pointOrBox[0] === 'number'; + if (isPoint) { + var point = Point.convert(pointOrBox); + queryGeometry = [point]; + } else { + var box = [ + Point.convert(pointOrBox[0]), + Point.convert(pointOrBox[1]) + ]; + queryGeometry = [ + box[0], + new Point(box[1].x, box[0].y), + box[1], + new Point(box[0].x, box[1].y), + box[0] + ]; + } + queryGeometry = queryGeometry.map(function (p) { + return this.transform.pointCoordinate(p); + }.bind(this)); + return queryGeometry; + }, + querySourceFeatures: function (sourceID, params) { + return this.style.querySourceFeatures(sourceID, params); + }, + setStyle: function (style) { + if (this.style) { + this.style.setEventedParent(null); + this.style._remove(); + this.off('rotate', this.style._redoPlacement); + this.off('pitch', this.style._redoPlacement); + } + if (!style) { + this.style = null; + return this; + } else if (style instanceof Style) { + this.style = style; + } else { + this.style = new Style(style, this); + } + this.style.setEventedParent(this, { style: this.style }); + this.on('rotate', this.style._redoPlacement); + this.on('pitch', this.style._redoPlacement); + return this; + }, + getStyle: function () { + if (this.style) { + return this.style.serialize(); + } + }, + addSource: function (id, source) { + this.style.addSource(id, source); + this._update(true); + return this; + }, + addSourceType: function (name, SourceType, callback) { + return this.style.addSourceType(name, SourceType, callback); + }, + removeSource: function (id) { + this.style.removeSource(id); + this._update(true); + return this; + }, + getSource: function (id) { + return this.style.getSource(id); + }, + addLayer: function (layer, before) { + this.style.addLayer(layer, before); + this._update(true); + return this; + }, + removeLayer: function (id) { + this.style.removeLayer(id); + this._update(true); + return this; + }, + getLayer: function (id) { + return this.style.getLayer(id); + }, + setFilter: function (layer, filter) { + this.style.setFilter(layer, filter); + this._update(true); + return this; + }, + setLayerZoomRange: function (layerId, minzoom, maxzoom) { + this.style.setLayerZoomRange(layerId, minzoom, maxzoom); + this._update(true); + return this; + }, + getFilter: function (layer) { + return this.style.getFilter(layer); + }, + setPaintProperty: function (layer, name, value, klass) { + this.style.setPaintProperty(layer, name, value, klass); + this._update(true); + return this; + }, + getPaintProperty: function (layer, name, klass) { + return this.style.getPaintProperty(layer, name, klass); + }, + setLayoutProperty: function (layer, name, value) { + this.style.setLayoutProperty(layer, name, value); + this._update(true); + return this; + }, + getLayoutProperty: function (layer, name) { + return this.style.getLayoutProperty(layer, name); + }, + getContainer: function () { + return this._container; + }, + getCanvasContainer: function () { + return this._canvasContainer; + }, + getCanvas: function () { + return this._canvas; + }, + _containerDimensions: function () { + var width = 0; + var height = 0; + if (this._container) { + width = this._container.offsetWidth || 400; + height = this._container.offsetHeight || 300; + } + return [ + width, + height + ]; + }, + _setupContainer: function () { + var container = this._container; + container.classList.add('mapboxgl-map'); + var canvasContainer = this._canvasContainer = DOM.create('div', 'mapboxgl-canvas-container', container); + if (this._interactive) { + canvasContainer.classList.add('mapboxgl-interactive'); + } + this._canvas = DOM.create('canvas', 'mapboxgl-canvas', canvasContainer); + this._canvas.style.position = 'absolute'; + this._canvas.addEventListener('webglcontextlost', this._contextLost, false); + this._canvas.addEventListener('webglcontextrestored', this._contextRestored, false); + this._canvas.setAttribute('tabindex', 0); + var dimensions = this._containerDimensions(); + this._resizeCanvas(dimensions[0], dimensions[1]); + var controlContainer = this._controlContainer = DOM.create('div', 'mapboxgl-control-container', container); + var corners = this._controlCorners = {}; + [ + 'top-left', + 'top-right', + 'bottom-left', + 'bottom-right' + ].forEach(function (pos) { + corners[pos] = DOM.create('div', 'mapboxgl-ctrl-' + pos, controlContainer); + }); + }, + _resizeCanvas: function (width, height) { + var pixelRatio = window.devicePixelRatio || 1; + this._canvas.width = pixelRatio * width; + this._canvas.height = pixelRatio * height; + this._canvas.style.width = width + 'px'; + this._canvas.style.height = height + 'px'; + }, + _setupPainter: function () { + var attributes = util.extend({ + failIfMajorPerformanceCaveat: this._failIfMajorPerformanceCaveat, + preserveDrawingBuffer: this._preserveDrawingBuffer + }, isSupported.webGLContextAttributes); + var gl = this._canvas.getContext('webgl', attributes) || this._canvas.getContext('experimental-webgl', attributes); + if (!gl) { + this.fire('error', { error: new Error('Failed to initialize WebGL') }); + return; + } + this.painter = new Painter(gl, this.transform); + }, + _contextLost: function (event) { + event.preventDefault(); + if (this._frameId) { + browser.cancelFrame(this._frameId); + } + this.fire('webglcontextlost', { originalEvent: event }); + }, + _contextRestored: function (event) { + this._setupPainter(); + this.resize(); + this._update(); + this.fire('webglcontextrestored', { originalEvent: event }); + }, + loaded: function () { + if (this._styleDirty || this._sourcesDirty) + return false; + if (!this.style || !this.style.loaded()) + return false; + return true; + }, + _update: function (updateStyle) { + if (!this.style) + return this; + this._styleDirty = this._styleDirty || updateStyle; + this._sourcesDirty = true; + this._rerender(); + return this; + }, + _render: function () { + try { + if (this.style && this._styleDirty) { + this._styleDirty = false; + this.style.update(this._classes, this._classOptions); + this._classOptions = null; + this.style._recalculate(this.transform.zoom); + } + if (this.style && this._sourcesDirty) { + this._sourcesDirty = false; + this.style._updateSources(this.transform); + } + this.painter.render(this.style, { + debug: this.showTileBoundaries, + showOverdrawInspector: this._showOverdrawInspector, + vertices: this.vertices, + rotating: this.rotating, + zooming: this.zooming + }); + this.fire('render'); + if (this.loaded() && !this._loaded) { + this._loaded = true; + this.fire('load'); + } + this._frameId = null; + if (!this.animationLoop.stopped()) { + this._styleDirty = true; + } + if (this._sourcesDirty || this._repaint || this._styleDirty) { + this._rerender(); + } + } catch (error) { + this.fire('error', { error: error }); + } + return this; + }, + remove: function () { + if (this._hash) + this._hash.remove(); + browser.cancelFrame(this._frameId); + this.setStyle(null); + if (typeof window !== 'undefined') { + window.removeEventListener('resize', this._onWindowResize, false); + } + var extension = this.painter.gl.getExtension('WEBGL_lose_context'); + if (extension) + extension.loseContext(); + removeNode(this._canvasContainer); + removeNode(this._controlContainer); + this._container.classList.remove('mapboxgl-map'); + this.fire('remove'); + }, + _rerender: function () { + if (this.style && !this._frameId) { + this._frameId = browser.frame(this._render); + } + }, + _onWindowOnline: function () { + this._update(); + }, + _onWindowResize: function () { + if (this._trackResize) { + this.stop().resize()._update(); + } + } +}); +util.extendAll(Map.prototype, { + _showTileBoundaries: false, + get showTileBoundaries() { + return this._showTileBoundaries; + }, + set showTileBoundaries(value) { + if (this._showTileBoundaries === value) + return; + this._showTileBoundaries = value; + this._update(); + }, + _showCollisionBoxes: false, + get showCollisionBoxes() { + return this._showCollisionBoxes; + }, + set showCollisionBoxes(value) { + if (this._showCollisionBoxes === value) + return; + this._showCollisionBoxes = value; + this.style._redoPlacement(); + }, + _showOverdrawInspector: false, + get showOverdrawInspector() { + return this._showOverdrawInspector; + }, + set showOverdrawInspector(value) { + if (this._showOverdrawInspector === value) + return; + this._showOverdrawInspector = value; + this._update(); + }, + _repaint: false, + get repaint() { + return this._repaint; + }, + set repaint(value) { + this._repaint = value; + this._update(); + }, + _vertices: false, + get vertices() { + return this._vertices; + }, + set vertices(value) { + this._vertices = value; + this._update(); } - // calculate coefficients - if ( (1.0 - cosom) > 0.000001 ) { - // standard case (slerp) - omega = Math.acos(cosom); - sinom = Math.sin(omega); - scale0 = Math.sin((1.0 - t) * omega) / sinom; - scale1 = Math.sin(t * omega) / sinom; - } else { - // "from" and "to" quaternions are very close - // ... so we can do a linear interpolation - scale0 = 1.0 - t; - scale1 = t; +}); +function removeNode(node) { + if (node.parentNode) { + node.parentNode.removeChild(node); + } +} +},{"../geo/lng_lat":82,"../geo/lng_lat_bounds":83,"../geo/transform":84,"../render/painter":99,"../style/animation_loop":119,"../style/style":122,"../util/browser":171,"../util/dom":178,"../util/evented":179,"../util/util":188,"../util/window":173,"./bind_handlers":151,"./camera":152,"./control/attribution":153,"./hash":165,"mapbox-gl-supported":70,"point-geometry":196}],167:[function(require,module,exports){ +'use strict'; +module.exports = Marker; +var DOM = require('../util/dom'); +var util = require('../util/util'); +var LngLat = require('../geo/lng_lat'); +var Point = require('point-geometry'); +var Popup = require('./popup'); +function Marker(element, options) { + this._offset = Point.convert(options && options.offset || [ + 0, + 0 + ]); + this._update = this._update.bind(this); + this._onMapClick = this._onMapClick.bind(this); + if (!element) + element = DOM.create('div'); + element.classList.add('mapboxgl-marker'); + this._element = element; + this._popup = null; +} +Marker.prototype = { + addTo: function (map) { + this.remove(); + this._map = map; + map.getCanvasContainer().appendChild(this._element); + map.on('move', this._update.bind(this)); + map.on('moveend', this._update.bind(this, { roundPos: true })); + this._update({ roundPos: true }); + this._map.on('click', this._onMapClick); + return this; + }, + remove: function () { + if (this._map) { + this._map.off('click', this._onMapClick); + this._map.off('move', this._update); + this._map = null; + } + DOM.remove(this._element); + if (this._popup) + this._popup.remove(); + return this; + }, + getLngLat: function () { + return this._lngLat; + }, + setLngLat: function (lnglat) { + this._lngLat = LngLat.convert(lnglat); + if (this._popup) + this._popup.setLngLat(this._lngLat); + this._update(); + return this; + }, + getElement: function () { + return this._element; + }, + setPopup: function (popup) { + var that = this; + if (this._popup) { + this._popup.remove(); + this._popup = null; + } + if (popup) { + this._popup = popup; + this._popup.setLngLat(this._lngLat); + } + return this; + }, + _onMapClick: function (event) { + var targetElement = event.originalEvent.target; + var element = this._element; + if (this._popup && (targetElement === element || element.contains(targetElement))) { + this.togglePopup(); + } + }, + getPopup: function () { + return this._popup; + }, + togglePopup: function () { + var popup = this._popup; + if (!popup) + return; + else if (popup.isOpen()) + popup.remove(); + else + popup.addTo(this._map); + }, + _update: function (options) { + if (!this._map) + return; + var pos = this._map.project(this._lngLat)._add(this._offset); + if (options.roundPos) + pos = pos.round(); + DOM.setTransform(this._element, 'translate(' + pos.x + 'px,' + pos.y + 'px)'); } - // calculate final values - out[0] = scale0 * ax + scale1 * bx; - out[1] = scale0 * ay + scale1 * by; - out[2] = scale0 * az + scale1 * bz; - out[3] = scale0 * aw + scale1 * bw; - - return out; -}; - -/** - * Performs a spherical linear interpolation with two control points - * - * @param {quat} out the receiving quaternion - * @param {quat} a the first operand - * @param {quat} b the second operand - * @param {quat} c the third operand - * @param {quat} d the fourth operand - * @param {Number} t interpolation amount - * @returns {quat} out - */ -quat.sqlerp = (function () { - var temp1 = quat.create(); - var temp2 = quat.create(); - - return function (out, a, b, c, d, t) { - quat.slerp(temp1, a, d, t); - quat.slerp(temp2, b, c, t); - quat.slerp(out, temp1, temp2, 2 * t * (1 - t)); - - return out; - }; -}()); - -/** - * Calculates the inverse of a quat - * - * @param {quat} out the receiving quaternion - * @param {quat} a quat to calculate inverse of - * @returns {quat} out - */ -quat.invert = function(out, a) { - var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], - dot = a0*a0 + a1*a1 + a2*a2 + a3*a3, - invDot = dot ? 1.0/dot : 0; - - // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 - - out[0] = -a0*invDot; - out[1] = -a1*invDot; - out[2] = -a2*invDot; - out[3] = a3*invDot; - return out; }; - -/** - * Calculates the conjugate of a quat - * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result. - * - * @param {quat} out the receiving quaternion - * @param {quat} a quat to calculate conjugate of - * @returns {quat} out - */ -quat.conjugate = function (out, a) { - out[0] = -a[0]; - out[1] = -a[1]; - out[2] = -a[2]; - out[3] = a[3]; - return out; +},{"../geo/lng_lat":82,"../util/dom":178,"../util/util":188,"./popup":168,"point-geometry":196}],168:[function(require,module,exports){ +'use strict'; +module.exports = Popup; +var util = require('../util/util'); +var Evented = require('../util/evented'); +var DOM = require('../util/dom'); +var LngLat = require('../geo/lng_lat'); +var Point = require('point-geometry'); +var window = require('../util/window'); +function Popup(options) { + util.setOptions(this, options); + util.bindAll([ + '_update', + '_onClickClose' + ], this); +} +Popup.prototype = util.inherit(Evented, { + options: { + closeButton: true, + closeOnClick: true + }, + addTo: function (map) { + this._map = map; + this._map.on('move', this._update); + if (this.options.closeOnClick) { + this._map.on('click', this._onClickClose); + } + this._update(); + return this; + }, + isOpen: function () { + return !!this._map; + }, + remove: function () { + if (this._content && this._content.parentNode) { + this._content.parentNode.removeChild(this._content); + } + if (this._container) { + this._container.parentNode.removeChild(this._container); + delete this._container; + } + if (this._map) { + this._map.off('move', this._update); + this._map.off('click', this._onClickClose); + delete this._map; + } + this.fire('close'); + return this; + }, + getLngLat: function () { + return this._lngLat; + }, + setLngLat: function (lnglat) { + this._lngLat = LngLat.convert(lnglat); + this._update(); + return this; + }, + setText: function (text) { + return this.setDOMContent(window.document.createTextNode(text)); + }, + setHTML: function (html) { + var frag = window.document.createDocumentFragment(); + var temp = window.document.createElement('body'), child; + temp.innerHTML = html; + while (true) { + child = temp.firstChild; + if (!child) + break; + frag.appendChild(child); + } + return this.setDOMContent(frag); + }, + setDOMContent: function (htmlNode) { + this._createContent(); + this._content.appendChild(htmlNode); + this._update(); + return this; + }, + _createContent: function () { + if (this._content && this._content.parentNode) { + this._content.parentNode.removeChild(this._content); + } + this._content = DOM.create('div', 'mapboxgl-popup-content', this._container); + if (this.options.closeButton) { + this._closeButton = DOM.create('button', 'mapboxgl-popup-close-button', this._content); + this._closeButton.type = 'button'; + this._closeButton.innerHTML = '×'; + this._closeButton.addEventListener('click', this._onClickClose); + } + }, + _update: function () { + if (!this._map || !this._lngLat || !this._content) { + return; + } + if (!this._container) { + this._container = DOM.create('div', 'mapboxgl-popup', this._map.getContainer()); + this._tip = DOM.create('div', 'mapboxgl-popup-tip', this._container); + this._container.appendChild(this._content); + } + var anchor = this.options.anchor; + var offset = normalizeOffset(this.options.offset); + var pos = this._map.project(this._lngLat).round(); + if (!anchor) { + var width = this._container.offsetWidth, height = this._container.offsetHeight; + if (pos.y < height) { + anchor = ['top']; + } else if (pos.y > this._map.transform.height - height) { + anchor = ['bottom']; + } else { + anchor = []; + } + if (pos.x < width / 2) { + anchor.push('left'); + } else if (pos.x > this._map.transform.width - width / 2) { + anchor.push('right'); + } + if (anchor.length === 0) { + anchor = 'bottom'; + } else { + anchor = anchor.join('-'); + } + } + var offsetedPos = pos.add(offset[anchor]); + var anchorTranslate = { + 'top': 'translate(-50%,0)', + 'top-left': 'translate(0,0)', + 'top-right': 'translate(-100%,0)', + 'bottom': 'translate(-50%,-100%)', + 'bottom-left': 'translate(0,-100%)', + 'bottom-right': 'translate(-100%,-100%)', + 'left': 'translate(0,-50%)', + 'right': 'translate(-100%,-50%)' + }; + var classList = this._container.classList; + for (var key in anchorTranslate) { + classList.remove('mapboxgl-popup-anchor-' + key); + } + classList.add('mapboxgl-popup-anchor-' + anchor); + DOM.setTransform(this._container, anchorTranslate[anchor] + ' translate(' + offsetedPos.x + 'px,' + offsetedPos.y + 'px)'); + }, + _onClickClose: function () { + this.remove(); + } +}); +function normalizeOffset(offset) { + if (!offset) { + return normalizeOffset(new Point(0, 0)); + } else if (typeof offset === 'number') { + var cornerOffset = Math.round(Math.sqrt(0.5 * Math.pow(offset, 2))); + return { + 'top': new Point(0, offset), + 'top-left': new Point(cornerOffset, cornerOffset), + 'top-right': new Point(-cornerOffset, cornerOffset), + 'bottom': new Point(0, -offset), + 'bottom-left': new Point(cornerOffset, -cornerOffset), + 'bottom-right': new Point(-cornerOffset, -cornerOffset), + 'left': new Point(offset, 0), + 'right': new Point(-offset, 0) + }; + } else if (isPointLike(offset)) { + var convertedOffset = Point.convert(offset); + return { + 'top': convertedOffset, + 'top-left': convertedOffset, + 'top-right': convertedOffset, + 'bottom': convertedOffset, + 'bottom-left': convertedOffset, + 'bottom-right': convertedOffset, + 'left': convertedOffset, + 'right': convertedOffset + }; + } else { + return { + 'top': Point.convert(offset['top']), + 'top-left': Point.convert(offset['top-left']), + 'top-right': Point.convert(offset['top-right']), + 'bottom': Point.convert(offset['bottom']), + 'bottom-left': Point.convert(offset['bottom-left']), + 'bottom-right': Point.convert(offset['bottom-right']), + 'left': Point.convert(offset['left']), + 'right': Point.convert(offset['right']) + }; + } +} +function isPointLike(input) { + return input instanceof Point || Array.isArray(input); +} +},{"../geo/lng_lat":82,"../util/dom":178,"../util/evented":179,"../util/util":188,"../util/window":173,"point-geometry":196}],169:[function(require,module,exports){ +'use strict'; +module.exports = Actor; +function Actor(target, parent, mapId) { + this.target = target; + this.parent = parent; + this.mapId = mapId; + this.callbacks = {}; + this.callbackID = 0; + this.receive = this.receive.bind(this); + this.target.addEventListener('message', this.receive, false); +} +Actor.prototype.send = function (type, data, callback, buffers, targetMapId) { + var id = callback ? this.mapId + ':' + this.callbackID++ : null; + if (callback) + this.callbacks[id] = callback; + this.target.postMessage({ + targetMapId: targetMapId, + sourceMapId: this.mapId, + type: type, + id: String(id), + data: data + }, buffers); }; - -/** - * Calculates the length of a quat - * - * @param {quat} a vector to calculate length of - * @returns {Number} length of a - * @function - */ -quat.length = vec4.length; - -/** - * Alias for {@link quat.length} - * @function - */ -quat.len = quat.length; - -/** - * Calculates the squared length of a quat - * - * @param {quat} a vector to calculate squared length of - * @returns {Number} squared length of a - * @function - */ -quat.squaredLength = vec4.squaredLength; - -/** - * Alias for {@link quat.squaredLength} - * @function - */ -quat.sqrLen = quat.squaredLength; - -/** - * Normalize a quat - * - * @param {quat} out the receiving quaternion - * @param {quat} a quaternion to normalize - * @returns {quat} out - * @function - */ -quat.normalize = vec4.normalize; - -/** - * Creates a quaternion from the given 3x3 rotation matrix. - * - * NOTE: The resultant quaternion is not normalized, so you should be sure - * to renormalize the quaternion yourself where necessary. - * - * @param {quat} out the receiving quaternion - * @param {mat3} m rotation matrix - * @returns {quat} out - * @function - */ -quat.fromMat3 = function(out, m) { - // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes - // article "Quaternion Calculus and Fast Animation". - var fTrace = m[0] + m[4] + m[8]; - var fRoot; - - if ( fTrace > 0.0 ) { - // |w| > 1/2, may as well choose w > 1/2 - fRoot = Math.sqrt(fTrace + 1.0); // 2w - out[3] = 0.5 * fRoot; - fRoot = 0.5/fRoot; // 1/(4w) - out[0] = (m[5]-m[7])*fRoot; - out[1] = (m[6]-m[2])*fRoot; - out[2] = (m[1]-m[3])*fRoot; +Actor.prototype.receive = function (message) { + var data = message.data, id = data.id, callback; + if (data.targetMapId && this.mapId !== data.targetMapId) + return; + if (data.type === '') { + callback = this.callbacks[data.id]; + delete this.callbacks[data.id]; + if (callback) + callback(data.error || null, data.data); + } else if (typeof data.id !== 'undefined' && this.parent[data.type]) { + this.parent[data.type](data.sourceMapId, data.data, done.bind(this)); + } else if (typeof data.id !== 'undefined' && this.parent.getWorkerSource) { + var keys = data.type.split('.'); + var workerSource = this.parent.getWorkerSource(data.sourceMapId, keys[0]); + workerSource[keys[1]](data.data, done.bind(this)); } else { - // |w| <= 1/2 - var i = 0; - if ( m[4] > m[0] ) - i = 1; - if ( m[8] > m[i*3+i] ) - i = 2; - var j = (i+1)%3; - var k = (i+2)%3; - - fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0); - out[i] = 0.5 * fRoot; - fRoot = 0.5 / fRoot; - out[3] = (m[j*3+k] - m[k*3+j]) * fRoot; - out[j] = (m[j*3+i] + m[i*3+j]) * fRoot; - out[k] = (m[k*3+i] + m[i*3+k]) * fRoot; + this.parent[data.type](data.data); + } + function done(err, data, buffers) { + this.target.postMessage({ + sourceMapId: this.mapId, + type: '', + id: String(id), + error: err ? String(err) : null, + data: data + }, buffers); } - - return out; }; - -/** - * Returns a string representation of a quatenion - * - * @param {quat} vec vector to represent as a string - * @returns {String} string representation of the vector - */ -quat.str = function (a) { - return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; +Actor.prototype.remove = function () { + this.target.removeEventListener('message', this.receive, false); }; - -module.exports = quat; - -},{"./common.js":124,"./mat3.js":127,"./vec3.js":131,"./vec4.js":132}],130:[function(require,module,exports){ -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -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. */ - -var glMatrix = require("./common.js"); - -/** - * @class 2 Dimensional Vector - * @name vec2 - */ -var vec2 = {}; - -/** - * Creates a new, empty vec2 - * - * @returns {vec2} a new 2D vector - */ -vec2.create = function() { - var out = new glMatrix.ARRAY_TYPE(2); - out[0] = 0; - out[1] = 0; - return out; +},{}],170:[function(require,module,exports){ +'use strict'; +var window = require('./window'); +exports.getJSON = function (url, callback) { + var xhr = new window.XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.setRequestHeader('Accept', 'application/json'); + xhr.onerror = function (e) { + callback(e); + }; + xhr.onload = function () { + if (xhr.status >= 200 && xhr.status < 300 && xhr.response) { + var data; + try { + data = JSON.parse(xhr.response); + } catch (err) { + return callback(err); + } + callback(null, data); + } else { + callback(new Error(xhr.statusText)); + } + }; + xhr.send(); + return xhr; }; - -/** - * Creates a new vec2 initialized with values from an existing vector - * - * @param {vec2} a vector to clone - * @returns {vec2} a new 2D vector - */ -vec2.clone = function(a) { - var out = new glMatrix.ARRAY_TYPE(2); - out[0] = a[0]; - out[1] = a[1]; - return out; +exports.getArrayBuffer = function (url, callback) { + var xhr = new window.XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.responseType = 'arraybuffer'; + xhr.onerror = function (e) { + callback(e); + }; + xhr.onload = function () { + if (xhr.status >= 200 && xhr.status < 300 && xhr.response) { + callback(null, xhr.response); + } else { + callback(new Error(xhr.statusText)); + } + }; + xhr.send(); + return xhr; }; - -/** - * Creates a new vec2 initialized with the given values - * - * @param {Number} x X component - * @param {Number} y Y component - * @returns {vec2} a new 2D vector - */ -vec2.fromValues = function(x, y) { - var out = new glMatrix.ARRAY_TYPE(2); - out[0] = x; - out[1] = y; - return out; +function sameOrigin(url) { + var a = window.document.createElement('a'); + a.href = url; + return a.protocol === window.document.location.protocol && a.host === window.document.location.host; +} +exports.getImage = function (url, callback) { + return exports.getArrayBuffer(url, function (err, imgData) { + if (err) + return callback(err); + var img = new window.Image(); + img.onload = function () { + callback(null, img); + (window.URL || window.webkitURL).revokeObjectURL(img.src); + }; + var blob = new window.Blob([new Uint8Array(imgData)], { type: 'image/png' }); + img.src = (window.URL || window.webkitURL).createObjectURL(blob); + img.getData = function () { + var canvas = window.document.createElement('canvas'); + var context = canvas.getContext('2d'); + canvas.width = img.width; + canvas.height = img.height; + context.drawImage(img, 0, 0); + return context.getImageData(0, 0, img.width, img.height).data; + }; + return img; + }); +}; +exports.getVideo = function (urls, callback) { + var video = window.document.createElement('video'); + video.onloadstart = function () { + callback(null, video); + }; + for (var i = 0; i < urls.length; i++) { + var s = window.document.createElement('source'); + if (!sameOrigin(urls[i])) { + video.crossOrigin = 'Anonymous'; + } + s.src = urls[i]; + video.appendChild(s); + } + video.getData = function () { + return video; + }; + return video; +}; +},{"./window":173}],171:[function(require,module,exports){ +'use strict'; +var window = require('./window'); +module.exports.now = function () { + if (window.performance && window.performance.now) { + return window.performance.now.bind(window.performance); + } else { + return Date.now.bind(Date); + } +}(); +var frame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; +exports.frame = function (fn) { + return frame(fn); +}; +var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame || window.msCancelAnimationFrame; +exports.cancelFrame = function (id) { + cancel(id); +}; +exports.timed = function (fn, dur, ctx) { + if (!dur) { + fn.call(ctx, 1); + return null; + } + var abort = false, start = module.exports.now(); + function tick(now) { + if (abort) + return; + now = module.exports.now(); + if (now >= start + dur) { + fn.call(ctx, 1); + } else { + fn.call(ctx, (now - start) / dur); + exports.frame(tick); + } + } + exports.frame(tick); + return function () { + abort = true; + }; }; - -/** - * Copy the values from one vec2 to another - * - * @param {vec2} out the receiving vector - * @param {vec2} a the source vector - * @returns {vec2} out - */ -vec2.copy = function(out, a) { - out[0] = a[0]; - out[1] = a[1]; - return out; +exports.supported = require('mapbox-gl-supported'); +exports.hardwareConcurrency = window.navigator.hardwareConcurrency || 4; +Object.defineProperty(exports, 'devicePixelRatio', { + get: function () { + return window.devicePixelRatio; + } +}); +exports.supportsWebp = false; +var webpImgTest = window.document.createElement('img'); +webpImgTest.onload = function () { + exports.supportsWebp = true; }; - -/** - * Set the components of a vec2 to the given values - * - * @param {vec2} out the receiving vector - * @param {Number} x X component - * @param {Number} y Y component - * @returns {vec2} out - */ -vec2.set = function(out, x, y) { - out[0] = x; - out[1] = y; - return out; +webpImgTest.src = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAQAAAAfQ//73v/+BiOh/AAA='; +exports.supportsGeolocation = !!window.navigator.geolocation; +},{"./window":173,"mapbox-gl-supported":70}],172:[function(require,module,exports){ +'use strict'; +var WebWorkify = require('webworkify'); +var window = require('../window'); +var workerURL = window.URL.createObjectURL(new WebWorkify(require('../../source/worker'), { bare: true })); +module.exports = function () { + return new window.Worker(workerURL); }; - -/** - * Adds two vec2's - * - * @param {vec2} out the receiving vector - * @param {vec2} a the first operand - * @param {vec2} b the second operand - * @returns {vec2} out - */ -vec2.add = function(out, a, b) { - out[0] = a[0] + b[0]; - out[1] = a[1] + b[1]; - return out; +},{"../../source/worker":117,"../window":173,"webworkify":221}],173:[function(require,module,exports){ +'use strict'; +module.exports = self; +},{}],174:[function(require,module,exports){ +'use strict'; +var quickselect = require('quickselect'); +var calculateSignedArea = require('./util').calculateSignedArea; +module.exports = function classifyRings(rings, maxRings) { + var len = rings.length; + if (len <= 1) + return [rings]; + var polygons = [], polygon, ccw; + for (var i = 0; i < len; i++) { + var area = calculateSignedArea(rings[i]); + if (area === 0) + continue; + rings[i].area = Math.abs(area); + if (ccw === undefined) + ccw = area < 0; + if (ccw === area < 0) { + if (polygon) + polygons.push(polygon); + polygon = [rings[i]]; + } else { + polygon.push(rings[i]); + } + } + if (polygon) + polygons.push(polygon); + if (maxRings > 1) { + for (var j = 0; j < polygons.length; j++) { + if (polygons[j].length <= maxRings) + continue; + quickselect(polygons[j], maxRings, 1, polygons[j].length - 1, compareAreas); + polygons[j] = polygons[j].slice(0, maxRings); + } + } + return polygons; }; - -/** - * Subtracts vector b from vector a - * - * @param {vec2} out the receiving vector - * @param {vec2} a the first operand - * @param {vec2} b the second operand - * @returns {vec2} out - */ -vec2.subtract = function(out, a, b) { - out[0] = a[0] - b[0]; - out[1] = a[1] - b[1]; - return out; +function compareAreas(a, b) { + return b.area - a.area; +} +},{"./util":188,"quickselect":202}],175:[function(require,module,exports){ +'use strict'; +module.exports = { + API_URL: 'https://api.mapbox.com', + REQUIRE_ACCESS_TOKEN: true }; - -/** - * Alias for {@link vec2.subtract} - * @function - */ -vec2.sub = vec2.subtract; - -/** - * Multiplies two vec2's - * - * @param {vec2} out the receiving vector - * @param {vec2} a the first operand - * @param {vec2} b the second operand - * @returns {vec2} out - */ -vec2.multiply = function(out, a, b) { - out[0] = a[0] * b[0]; - out[1] = a[1] * b[1]; - return out; +},{}],176:[function(require,module,exports){ +'use strict'; +module.exports = DictionaryCoder; +function DictionaryCoder(strings) { + this._stringToNumber = {}; + this._numberToString = []; + for (var i = 0; i < strings.length; i++) { + var string = strings[i]; + this._stringToNumber[string] = i; + this._numberToString[i] = string; + } +} +DictionaryCoder.prototype.encode = function (string) { + return this._stringToNumber[string]; }; - -/** - * Alias for {@link vec2.multiply} - * @function - */ -vec2.mul = vec2.multiply; - -/** - * Divides two vec2's - * - * @param {vec2} out the receiving vector - * @param {vec2} a the first operand - * @param {vec2} b the second operand - * @returns {vec2} out - */ -vec2.divide = function(out, a, b) { - out[0] = a[0] / b[0]; - out[1] = a[1] / b[1]; - return out; +DictionaryCoder.prototype.decode = function (n) { + return this._numberToString[n]; }; - -/** - * Alias for {@link vec2.divide} - * @function - */ -vec2.div = vec2.divide; - -/** - * Returns the minimum of two vec2's - * - * @param {vec2} out the receiving vector - * @param {vec2} a the first operand - * @param {vec2} b the second operand - * @returns {vec2} out - */ -vec2.min = function(out, a, b) { - out[0] = Math.min(a[0], b[0]); - out[1] = Math.min(a[1], b[1]); - return out; +},{}],177:[function(require,module,exports){ +'use strict'; +var util = require('./util'); +var Actor = require('./actor'); +module.exports = Dispatcher; +function Dispatcher(workerPool, parent) { + this.workerPool = workerPool; + this.actors = []; + this.currentActor = 0; + this.id = util.uniqueId(); + var workers = this.workerPool.acquire(this.id); + for (var i = 0; i < workers.length; i++) { + var worker = workers[i]; + var actor = new Actor(worker, parent, this.id); + actor.name = 'Worker ' + i; + this.actors.push(actor); + } +} +Dispatcher.prototype = { + broadcast: function (type, data, cb) { + cb = cb || function () { + }; + util.asyncAll(this.actors, function (actor, done) { + actor.send(type, data, done); + }, cb); + }, + send: function (type, data, callback, targetID, buffers) { + if (typeof targetID !== 'number' || isNaN(targetID)) { + targetID = this.currentActor = (this.currentActor + 1) % this.actors.length; + } + this.actors[targetID].send(type, data, callback, buffers); + return targetID; + }, + remove: function () { + this.actors.forEach(function (actor) { + actor.remove(); + }); + this.actors = []; + this.workerPool.release(this.id); + } }; - -/** - * Returns the maximum of two vec2's - * - * @param {vec2} out the receiving vector - * @param {vec2} a the first operand - * @param {vec2} b the second operand - * @returns {vec2} out - */ -vec2.max = function(out, a, b) { - out[0] = Math.max(a[0], b[0]); - out[1] = Math.max(a[1], b[1]); - return out; +},{"./actor":169,"./util":188}],178:[function(require,module,exports){ +'use strict'; +var Point = require('point-geometry'); +var window = require('./window'); +exports.create = function (tagName, className, container) { + var el = window.document.createElement(tagName); + if (className) + el.className = className; + if (container) + container.appendChild(el); + return el; }; - -/** - * Scales a vec2 by a scalar number - * - * @param {vec2} out the receiving vector - * @param {vec2} a the vector to scale - * @param {Number} b amount to scale the vector by - * @returns {vec2} out - */ -vec2.scale = function(out, a, b) { - out[0] = a[0] * b; - out[1] = a[1] * b; - return out; +var docStyle = window.document.documentElement.style; +function testProp(props) { + for (var i = 0; i < props.length; i++) { + if (props[i] in docStyle) { + return props[i]; + } + } + return props[0]; +} +var selectProp = testProp([ + 'userSelect', + 'MozUserSelect', + 'WebkitUserSelect', + 'msUserSelect' + ]), userSelect; +exports.disableDrag = function () { + if (selectProp) { + userSelect = docStyle[selectProp]; + docStyle[selectProp] = 'none'; + } }; - -/** - * Adds two vec2's after scaling the second operand by a scalar value - * - * @param {vec2} out the receiving vector - * @param {vec2} a the first operand - * @param {vec2} b the second operand - * @param {Number} scale the amount to scale b by before adding - * @returns {vec2} out - */ -vec2.scaleAndAdd = function(out, a, b, scale) { - out[0] = a[0] + (b[0] * scale); - out[1] = a[1] + (b[1] * scale); - return out; +exports.enableDrag = function () { + if (selectProp) { + docStyle[selectProp] = userSelect; + } }; - -/** - * Calculates the euclidian distance between two vec2's - * - * @param {vec2} a the first operand - * @param {vec2} b the second operand - * @returns {Number} distance between a and b - */ -vec2.distance = function(a, b) { - var x = b[0] - a[0], - y = b[1] - a[1]; - return Math.sqrt(x*x + y*y); +var transformProp = testProp([ + 'transform', + 'WebkitTransform' +]); +exports.setTransform = function (el, value) { + el.style[transformProp] = value; }; - -/** - * Alias for {@link vec2.distance} - * @function - */ -vec2.dist = vec2.distance; - -/** - * Calculates the squared euclidian distance between two vec2's - * - * @param {vec2} a the first operand - * @param {vec2} b the second operand - * @returns {Number} squared distance between a and b - */ -vec2.squaredDistance = function(a, b) { - var x = b[0] - a[0], - y = b[1] - a[1]; - return x*x + y*y; +function suppressClick(e) { + e.preventDefault(); + e.stopPropagation(); + window.removeEventListener('click', suppressClick, true); +} +exports.suppressClick = function () { + window.addEventListener('click', suppressClick, true); + window.setTimeout(function () { + window.removeEventListener('click', suppressClick, true); + }, 0); +}; +exports.mousePos = function (el, e) { + var rect = el.getBoundingClientRect(); + e = e.touches ? e.touches[0] : e; + return new Point(e.clientX - rect.left - el.clientLeft, e.clientY - rect.top - el.clientTop); }; - -/** - * Alias for {@link vec2.squaredDistance} - * @function - */ -vec2.sqrDist = vec2.squaredDistance; - -/** - * Calculates the length of a vec2 - * - * @param {vec2} a vector to calculate length of - * @returns {Number} length of a - */ -vec2.length = function (a) { - var x = a[0], - y = a[1]; - return Math.sqrt(x*x + y*y); +exports.touchPos = function (el, e) { + var rect = el.getBoundingClientRect(), points = []; + for (var i = 0; i < e.touches.length; i++) { + points.push(new Point(e.touches[i].clientX - rect.left - el.clientLeft, e.touches[i].clientY - rect.top - el.clientTop)); + } + return points; }; - -/** - * Alias for {@link vec2.length} - * @function - */ -vec2.len = vec2.length; - -/** - * Calculates the squared length of a vec2 - * - * @param {vec2} a vector to calculate squared length of - * @returns {Number} squared length of a - */ -vec2.squaredLength = function (a) { - var x = a[0], - y = a[1]; - return x*x + y*y; +exports.remove = function (node) { + if (node.parentNode) { + node.parentNode.removeChild(node); + } }; - -/** - * Alias for {@link vec2.squaredLength} - * @function - */ -vec2.sqrLen = vec2.squaredLength; - -/** - * Negates the components of a vec2 - * - * @param {vec2} out the receiving vector - * @param {vec2} a vector to negate - * @returns {vec2} out - */ -vec2.negate = function(out, a) { - out[0] = -a[0]; - out[1] = -a[1]; - return out; +},{"./window":173,"point-geometry":196}],179:[function(require,module,exports){ +'use strict'; +var util = require('./util'); +var Evented = { + on: function (type, listener) { + this._listeners = this._listeners || {}; + this._listeners[type] = this._listeners[type] || []; + this._listeners[type].push(listener); + return this; + }, + off: function (type, listener) { + if (this._listeners && this._listeners[type]) { + var index = this._listeners[type].indexOf(listener); + if (index !== -1) { + this._listeners[type].splice(index, 1); + } + } + return this; + }, + once: function (type, listener) { + var wrapper = function (data) { + this.off(type, wrapper); + listener.call(this, data); + }.bind(this); + this.on(type, wrapper); + return this; + }, + fire: function (type, data) { + if (this.listens(type)) { + data = util.extend({}, data, { + type: type, + target: this + }); + var listeners = this._listeners && this._listeners[type] ? this._listeners[type].slice() : []; + for (var i = 0; i < listeners.length; i++) { + listeners[i].call(this, data); + } + if (this._eventedParent) { + this._eventedParent.fire(type, util.extend({}, data, this._eventedParentData)); + } + } else if (util.endsWith(type, 'error')) { + console.error(data && data.error || data || 'Empty error event'); + } + return this; + }, + listens: function (type) { + return this._listeners && this._listeners[type] || this._eventedParent && this._eventedParent.listens(type); + }, + setEventedParent: function (parent, data) { + this._eventedParent = parent; + this._eventedParentData = data; + return this; + } }; - -/** - * Returns the inverse of the components of a vec2 - * - * @param {vec2} out the receiving vector - * @param {vec2} a vector to invert - * @returns {vec2} out - */ -vec2.inverse = function(out, a) { - out[0] = 1.0 / a[0]; - out[1] = 1.0 / a[1]; - return out; +module.exports = Evented; +},{"./util":188}],180:[function(require,module,exports){ +'use strict'; +var Queue = require('tinyqueue'); +var Point = require('point-geometry'); +var distToSegmentSquared = require('./intersection_tests').distToSegmentSquared; +module.exports = function (polygonRings, precision, debug) { + precision = precision || 1; + var minX, minY, maxX, maxY; + var outerRing = polygonRings[0]; + for (var i = 0; i < outerRing.length; i++) { + var p = outerRing[i]; + if (!i || p.x < minX) + minX = p.x; + if (!i || p.y < minY) + minY = p.y; + if (!i || p.x > maxX) + maxX = p.x; + if (!i || p.y > maxY) + maxY = p.y; + } + var width = maxX - minX; + var height = maxY - minY; + var cellSize = Math.min(width, height); + var h = cellSize / 2; + var cellQueue = new Queue(null, compareMax); + for (var x = minX; x < maxX; x += cellSize) { + for (var y = minY; y < maxY; y += cellSize) { + cellQueue.push(new Cell(x + h, y + h, h, polygonRings)); + } + } + var bestCell = getCentroidCell(polygonRings); + var numProbes = cellQueue.length; + while (cellQueue.length) { + var cell = cellQueue.pop(); + if (cell.d > bestCell.d) { + bestCell = cell; + if (debug) + console.log('found best %d after %d probes', Math.round(10000 * cell.d) / 10000, numProbes); + } + if (cell.max - bestCell.d <= precision) + continue; + h = cell.h / 2; + cellQueue.push(new Cell(cell.p.x - h, cell.p.y - h, h, polygonRings)); + cellQueue.push(new Cell(cell.p.x + h, cell.p.y - h, h, polygonRings)); + cellQueue.push(new Cell(cell.p.x - h, cell.p.y + h, h, polygonRings)); + cellQueue.push(new Cell(cell.p.x + h, cell.p.y + h, h, polygonRings)); + numProbes += 4; + } + if (debug) { + console.log('num probes: ' + numProbes); + console.log('best distance: ' + bestCell.d); + } + return bestCell.p; }; - -/** - * Normalize a vec2 - * - * @param {vec2} out the receiving vector - * @param {vec2} a vector to normalize - * @returns {vec2} out - */ -vec2.normalize = function(out, a) { - var x = a[0], - y = a[1]; - var len = x*x + y*y; - if (len > 0) { - //TODO: evaluate use of glm_invsqrt here? - len = 1 / Math.sqrt(len); - out[0] = a[0] * len; - out[1] = a[1] * len; +function compareMax(a, b) { + return b.max - a.max; +} +function Cell(x, y, h, polygon) { + this.p = new Point(x, y); + this.h = h; + this.d = pointToPolygonDist(this.p, polygon); + this.max = this.d + this.h * Math.SQRT2; +} +function pointToPolygonDist(p, polygon) { + var inside = false; + var minDistSq = Infinity; + for (var k = 0; k < polygon.length; k++) { + var ring = polygon[k]; + for (var i = 0, len = ring.length, j = len - 1; i < len; j = i++) { + var a = ring[i]; + var b = ring[j]; + if (a.y > p.y !== b.y > p.y && p.x < (b.x - a.x) * (p.y - a.y) / (b.y - a.y) + a.x) + inside = !inside; + minDistSq = Math.min(minDistSq, distToSegmentSquared(p, a, b)); + } } - return out; + return (inside ? 1 : -1) * Math.sqrt(minDistSq); +} +function getCentroidCell(polygon) { + var area = 0; + var x = 0; + var y = 0; + var points = polygon[0]; + for (var i = 0, len = points.length, j = len - 1; i < len; j = i++) { + var a = points[i]; + var b = points[j]; + var f = a.x * b.y - b.x * a.y; + x += (a.x + b.x) * f; + y += (a.y + b.y) * f; + area += f * 3; + } + return new Cell(x / area, y / area, 0, polygon); +} +},{"./intersection_tests":183,"point-geometry":196,"tinyqueue":205}],181:[function(require,module,exports){ +'use strict'; +module.exports = Glyphs; +function Glyphs(pbf, end) { + this.stacks = pbf.readFields(readFontstacks, [], end); +} +function readFontstacks(tag, stacks, pbf) { + if (tag === 1) { + var fontstack = pbf.readMessage(readFontstack, { glyphs: {} }); + stacks.push(fontstack); + } +} +function readFontstack(tag, fontstack, pbf) { + if (tag === 1) + fontstack.name = pbf.readString(); + else if (tag === 2) + fontstack.range = pbf.readString(); + else if (tag === 3) { + var glyph = pbf.readMessage(readGlyph, {}); + fontstack.glyphs[glyph.id] = glyph; + } +} +function readGlyph(tag, glyph, pbf) { + if (tag === 1) + glyph.id = pbf.readVarint(); + else if (tag === 2) + glyph.bitmap = pbf.readBytes(); + else if (tag === 3) + glyph.width = pbf.readVarint(); + else if (tag === 4) + glyph.height = pbf.readVarint(); + else if (tag === 5) + glyph.left = pbf.readSVarint(); + else if (tag === 6) + glyph.top = pbf.readSVarint(); + else if (tag === 7) + glyph.advance = pbf.readVarint(); +} +},{}],182:[function(require,module,exports){ +'use strict'; +module.exports = interpolate; +function interpolate(a, b, t) { + return a * (1 - t) + b * t; +} +interpolate.number = interpolate; +interpolate.vec2 = function (from, to, t) { + return [ + interpolate(from[0], to[0], t), + interpolate(from[1], to[1], t) + ]; }; - -/** - * Calculates the dot product of two vec2's - * - * @param {vec2} a the first operand - * @param {vec2} b the second operand - * @returns {Number} dot product of a and b - */ -vec2.dot = function (a, b) { - return a[0] * b[0] + a[1] * b[1]; +interpolate.color = function (from, to, t) { + return [ + interpolate(from[0], to[0], t), + interpolate(from[1], to[1], t), + interpolate(from[2], to[2], t), + interpolate(from[3], to[3], t) + ]; }; - -/** - * Computes the cross product of two vec2's - * Note that the cross product must by definition produce a 3D vector - * - * @param {vec3} out the receiving vector - * @param {vec2} a the first operand - * @param {vec2} b the second operand - * @returns {vec3} out - */ -vec2.cross = function(out, a, b) { - var z = a[0] * b[1] - a[1] * b[0]; - out[0] = out[1] = 0; - out[2] = z; - return out; +interpolate.array = function (from, to, t) { + return from.map(function (d, i) { + return interpolate(d, to[i], t); + }); }; - -/** - * Performs a linear interpolation between two vec2's - * - * @param {vec2} out the receiving vector - * @param {vec2} a the first operand - * @param {vec2} b the second operand - * @param {Number} t interpolation amount between the two inputs - * @returns {vec2} out - */ -vec2.lerp = function (out, a, b, t) { - var ax = a[0], - ay = a[1]; - out[0] = ax + t * (b[0] - ax); - out[1] = ay + t * (b[1] - ay); - return out; +},{}],183:[function(require,module,exports){ +'use strict'; +var isCounterClockwise = require('./util').isCounterClockwise; +module.exports = { + multiPolygonIntersectsBufferedMultiPoint: multiPolygonIntersectsBufferedMultiPoint, + multiPolygonIntersectsMultiPolygon: multiPolygonIntersectsMultiPolygon, + multiPolygonIntersectsBufferedMultiLine: multiPolygonIntersectsBufferedMultiLine, + distToSegmentSquared: distToSegmentSquared +}; +function multiPolygonIntersectsBufferedMultiPoint(multiPolygon, rings, radius) { + for (var j = 0; j < multiPolygon.length; j++) { + var polygon = multiPolygon[j]; + for (var i = 0; i < rings.length; i++) { + var ring = rings[i]; + for (var k = 0; k < ring.length; k++) { + var point = ring[k]; + if (polygonContainsPoint(polygon, point)) + return true; + if (pointIntersectsBufferedLine(point, polygon, radius)) + return true; + } + } + } + return false; +} +function multiPolygonIntersectsMultiPolygon(multiPolygonA, multiPolygonB) { + if (multiPolygonA.length === 1 && multiPolygonA[0].length === 1) { + return multiPolygonContainsPoint(multiPolygonB, multiPolygonA[0][0]); + } + for (var m = 0; m < multiPolygonB.length; m++) { + var ring = multiPolygonB[m]; + for (var n = 0; n < ring.length; n++) { + if (multiPolygonContainsPoint(multiPolygonA, ring[n])) + return true; + } + } + for (var j = 0; j < multiPolygonA.length; j++) { + var polygon = multiPolygonA[j]; + for (var i = 0; i < polygon.length; i++) { + if (multiPolygonContainsPoint(multiPolygonB, polygon[i])) + return true; + } + for (var k = 0; k < multiPolygonB.length; k++) { + if (lineIntersectsLine(polygon, multiPolygonB[k])) + return true; + } + } + return false; +} +function multiPolygonIntersectsBufferedMultiLine(multiPolygon, multiLine, radius) { + for (var i = 0; i < multiLine.length; i++) { + var line = multiLine[i]; + for (var j = 0; j < multiPolygon.length; j++) { + var polygon = multiPolygon[j]; + if (polygon.length >= 3) { + for (var k = 0; k < line.length; k++) { + if (polygonContainsPoint(polygon, line[k])) + return true; + } + } + if (lineIntersectsBufferedLine(polygon, line, radius)) + return true; + } + } + return false; +} +function lineIntersectsBufferedLine(lineA, lineB, radius) { + if (lineA.length > 1) { + if (lineIntersectsLine(lineA, lineB)) + return true; + for (var j = 0; j < lineB.length; j++) { + if (pointIntersectsBufferedLine(lineB[j], lineA, radius)) + return true; + } + } + for (var k = 0; k < lineA.length; k++) { + if (pointIntersectsBufferedLine(lineA[k], lineB, radius)) + return true; + } + return false; +} +function lineIntersectsLine(lineA, lineB) { + for (var i = 0; i < lineA.length - 1; i++) { + var a0 = lineA[i]; + var a1 = lineA[i + 1]; + for (var j = 0; j < lineB.length - 1; j++) { + var b0 = lineB[j]; + var b1 = lineB[j + 1]; + if (lineSegmentIntersectsLineSegment(a0, a1, b0, b1)) + return true; + } + } + return false; +} +function lineSegmentIntersectsLineSegment(a0, a1, b0, b1) { + return isCounterClockwise(a0, b0, b1) !== isCounterClockwise(a1, b0, b1) && isCounterClockwise(a0, a1, b0) !== isCounterClockwise(a0, a1, b1); +} +function pointIntersectsBufferedLine(p, line, radius) { + var radiusSquared = radius * radius; + if (line.length === 1) + return p.distSqr(line[0]) < radiusSquared; + for (var i = 1; i < line.length; i++) { + var v = line[i - 1], w = line[i]; + if (distToSegmentSquared(p, v, w) < radiusSquared) + return true; + } + return false; +} +function distToSegmentSquared(p, v, w) { + var l2 = v.distSqr(w); + if (l2 === 0) + return p.distSqr(v); + var t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2; + if (t < 0) + return p.distSqr(v); + if (t > 1) + return p.distSqr(w); + return p.distSqr(w.sub(v)._mult(t)._add(v)); +} +function multiPolygonContainsPoint(rings, p) { + var c = false, ring, p1, p2; + for (var k = 0; k < rings.length; k++) { + ring = rings[k]; + for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) { + p1 = ring[i]; + p2 = ring[j]; + if (p1.y > p.y !== p2.y > p.y && p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x) { + c = !c; + } + } + } + return c; +} +function polygonContainsPoint(ring, p) { + var c = false; + for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) { + var p1 = ring[i]; + var p2 = ring[j]; + if (p1.y > p.y !== p2.y > p.y && p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x) { + c = !c; + } + } + return c; +} +},{"./util":188}],184:[function(require,module,exports){ +'use strict'; +module.exports = LRUCache; +function LRUCache(max, onRemove) { + this.max = max; + this.onRemove = onRemove; + this.reset(); +} +LRUCache.prototype.reset = function () { + for (var key in this.data) { + this.onRemove(this.data[key]); + } + this.data = {}; + this.order = []; + return this; }; - -/** - * Generates a random vector with the given scale - * - * @param {vec2} out the receiving vector - * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned - * @returns {vec2} out - */ -vec2.random = function (out, scale) { - scale = scale || 1.0; - var r = glMatrix.RANDOM() * 2.0 * Math.PI; - out[0] = Math.cos(r) * scale; - out[1] = Math.sin(r) * scale; - return out; +LRUCache.prototype.add = function (key, data) { + if (this.has(key)) { + this.order.splice(this.order.indexOf(key), 1); + this.data[key] = data; + this.order.push(key); + } else { + this.data[key] = data; + this.order.push(key); + if (this.order.length > this.max) { + var removedData = this.get(this.order[0]); + if (removedData) + this.onRemove(removedData); + } + } + return this; }; - -/** - * Transforms the vec2 with a mat2 - * - * @param {vec2} out the receiving vector - * @param {vec2} a the vector to transform - * @param {mat2} m matrix to transform with - * @returns {vec2} out - */ -vec2.transformMat2 = function(out, a, m) { - var x = a[0], - y = a[1]; - out[0] = m[0] * x + m[2] * y; - out[1] = m[1] * x + m[3] * y; - return out; +LRUCache.prototype.has = function (key) { + return key in this.data; }; - -/** - * Transforms the vec2 with a mat2d - * - * @param {vec2} out the receiving vector - * @param {vec2} a the vector to transform - * @param {mat2d} m matrix to transform with - * @returns {vec2} out - */ -vec2.transformMat2d = function(out, a, m) { - var x = a[0], - y = a[1]; - out[0] = m[0] * x + m[2] * y + m[4]; - out[1] = m[1] * x + m[3] * y + m[5]; - return out; +LRUCache.prototype.keys = function () { + return this.order; }; - -/** - * Transforms the vec2 with a mat3 - * 3rd vector component is implicitly '1' - * - * @param {vec2} out the receiving vector - * @param {vec2} a the vector to transform - * @param {mat3} m matrix to transform with - * @returns {vec2} out - */ -vec2.transformMat3 = function(out, a, m) { - var x = a[0], - y = a[1]; - out[0] = m[0] * x + m[3] * y + m[6]; - out[1] = m[1] * x + m[4] * y + m[7]; - return out; +LRUCache.prototype.get = function (key) { + if (!this.has(key)) { + return null; + } + var data = this.data[key]; + delete this.data[key]; + this.order.splice(this.order.indexOf(key), 1); + return data; }; - -/** - * Transforms the vec2 with a mat4 - * 3rd vector component is implicitly '0' - * 4th vector component is implicitly '1' - * - * @param {vec2} out the receiving vector - * @param {vec2} a the vector to transform - * @param {mat4} m matrix to transform with - * @returns {vec2} out - */ -vec2.transformMat4 = function(out, a, m) { - var x = a[0], - y = a[1]; - out[0] = m[0] * x + m[4] * y + m[12]; - out[1] = m[1] * x + m[5] * y + m[13]; - return out; +LRUCache.prototype.setMaxSize = function (max) { + this.max = max; + while (this.order.length > this.max) { + var removedData = this.get(this.order[0]); + if (removedData) + this.onRemove(removedData); + } + return this; }; - -/** - * Perform some operation over an array of vec2s. - * - * @param {Array} a the array of vectors to iterate over - * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed - * @param {Number} offset Number of elements to skip at the beginning of the array - * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array - * @param {Function} fn Function to call for each vector in the array - * @param {Object} [arg] additional argument to pass to fn - * @returns {Array} a - * @function - */ -vec2.forEach = (function() { - var vec = vec2.create(); - - return function(a, stride, offset, count, fn, arg) { - var i, l; - if(!stride) { - stride = 2; - } - - if(!offset) { - offset = 0; - } - - if(count) { - l = Math.min((count * stride) + offset, a.length); - } else { - l = a.length; +},{}],185:[function(require,module,exports){ +'use strict'; +var config = require('./config'); +var browser = require('./browser'); +var URL = require('url'); +var util = require('./util'); +function makeAPIURL(path, query, accessToken) { + accessToken = accessToken || config.ACCESS_TOKEN; + if (!accessToken && config.REQUIRE_ACCESS_TOKEN) { + throw new Error('An API access token is required to use Mapbox GL. ' + 'See https://www.mapbox.com/developers/api/#access-tokens'); + } + var url = config.API_URL + path + (query ? '?' + query : ''); + if (config.REQUIRE_ACCESS_TOKEN) { + if (accessToken[0] === 's') { + throw new Error('Use a public access token (pk.*) with Mapbox GL JS, not a secret access token (sk.*). ' + 'See https://www.mapbox.com/developers/api/#access-tokens'); } - - for(i = offset; i < l; i += stride) { - vec[0] = a[i]; vec[1] = a[i+1]; - fn(vec, vec, arg); - a[i] = vec[0]; a[i+1] = vec[1]; + url += (query ? '&' : '?') + 'access_token=' + accessToken; + } + return url; +} +module.exports.isMapboxURL = function (url) { + return URL.parse(url).protocol === 'mapbox:'; +}; +module.exports.normalizeStyleURL = function (url, accessToken) { + var urlObject = URL.parse(url); + if (urlObject.protocol !== 'mapbox:') { + return url; + } else { + return makeAPIURL('/styles/v1' + urlObject.pathname, urlObject.query, accessToken); + } +}; +module.exports.normalizeSourceURL = function (url, accessToken) { + var urlObject = URL.parse(url); + if (urlObject.protocol !== 'mapbox:') { + return url; + } else { + var sources = url.match(/mapbox:\/\/([^?]+)/)[1]; + return makeAPIURL('/v4/' + sources + '.json', urlObject.query, accessToken) + '&secure'; + } +}; +module.exports.normalizeGlyphsURL = function (url, accessToken) { + var urlObject = URL.parse(url); + if (urlObject.protocol !== 'mapbox:') { + return url; + } else { + var user = urlObject.pathname.split('/')[1]; + return makeAPIURL('/fonts/v1/' + user + '/{fontstack}/{range}.pbf', urlObject.query, accessToken); + } +}; +module.exports.normalizeSpriteURL = function (url, format, extension, accessToken) { + var urlObject = URL.parse(url); + if (urlObject.protocol !== 'mapbox:') { + urlObject.pathname += format + extension; + return URL.format(urlObject); + } else { + return makeAPIURL('/styles/v1' + urlObject.pathname + '/sprite' + format + extension, urlObject.query, accessToken); + } +}; +module.exports.normalizeTileURL = function (tileURL, sourceURL, tileSize) { + var tileURLObject = URL.parse(tileURL, true); + if (!sourceURL) + return tileURL; + var sourceURLObject = URL.parse(sourceURL); + if (sourceURLObject.protocol !== 'mapbox:') + return tileURL; + var extension = browser.supportsWebp ? '.webp' : '$1'; + var resolution = browser.devicePixelRatio >= 2 || tileSize === 512 ? '@2x' : ''; + return URL.format({ + protocol: tileURLObject.protocol, + hostname: tileURLObject.hostname, + pathname: tileURLObject.pathname.replace(/(\.(?:png|jpg)\d*)/, resolution + extension), + query: replaceTempAccessToken(tileURLObject.query) + }); +}; +function replaceTempAccessToken(query) { + if (query.access_token && query.access_token.slice(0, 3) === 'tk.') { + return util.extend({}, query, { 'access_token': config.ACCESS_TOKEN }); + } else { + return query; + } +} +},{"./browser":171,"./config":175,"./util":188,"url":207}],186:[function(require,module,exports){ +'use strict'; +module.exports = StructArrayType; +var viewTypes = { + 'Int8': Int8Array, + 'Uint8': Uint8Array, + 'Uint8Clamped': Uint8ClampedArray, + 'Int16': Int16Array, + 'Uint16': Uint16Array, + 'Int32': Int32Array, + 'Uint32': Uint32Array, + 'Float32': Float32Array, + 'Float64': Float64Array +}; +var structArrayTypeCache = {}; +function StructArrayType(options) { + var key = JSON.stringify(options); + if (structArrayTypeCache[key]) { + return structArrayTypeCache[key]; + } + if (options.alignment === undefined) + options.alignment = 1; + function StructType() { + Struct.apply(this, arguments); + } + StructType.prototype = Object.create(Struct.prototype); + var offset = 0; + var maxSize = 0; + var usedTypes = ['Uint8']; + StructType.prototype.members = options.members.map(function (member) { + member = { + name: member.name, + type: member.type, + components: member.components || 1 + }; + if (usedTypes.indexOf(member.type) < 0) + usedTypes.push(member.type); + var typeSize = sizeOf(member.type); + maxSize = Math.max(maxSize, typeSize); + member.offset = offset = align(offset, Math.max(options.alignment, typeSize)); + for (var c = 0; c < member.components; c++) { + Object.defineProperty(StructType.prototype, member.name + (member.components === 1 ? '' : c), { + get: createGetter(member, c), + set: createSetter(member, c) + }); } - - return a; + offset += typeSize * member.components; + return member; + }); + StructType.prototype.alignment = options.alignment; + StructType.prototype.size = align(offset, Math.max(maxSize, options.alignment)); + function StructArrayType() { + StructArray.apply(this, arguments); + this.members = StructType.prototype.members; + } + StructArrayType.serialize = serializeStructArrayType; + StructArrayType.prototype = Object.create(StructArray.prototype); + StructArrayType.prototype.StructType = StructType; + StructArrayType.prototype.bytesPerElement = StructType.prototype.size; + StructArrayType.prototype.emplaceBack = createEmplaceBack(StructType.prototype.members, StructType.prototype.size); + StructArrayType.prototype._usedTypes = usedTypes; + structArrayTypeCache[key] = StructArrayType; + return StructArrayType; +} +function serializeStructArrayType() { + return { + members: this.prototype.StructType.prototype.members, + alignment: this.prototype.StructType.prototype.alignment, + bytesPerElement: this.prototype.bytesPerElement + }; +} +function align(offset, size) { + return Math.ceil(offset / size) * size; +} +function sizeOf(type) { + return viewTypes[type].BYTES_PER_ELEMENT; +} +function getArrayViewName(type) { + return type.toLowerCase(); +} +function createEmplaceBack(members, bytesPerElement) { + var usedTypeSizes = []; + var argNames = []; + var body = '' + 'var i = this.length;\n' + 'this.resize(this.length + 1);\n'; + for (var m = 0; m < members.length; m++) { + var member = members[m]; + var size = sizeOf(member.type); + if (usedTypeSizes.indexOf(size) < 0) { + usedTypeSizes.push(size); + body += 'var o' + size.toFixed(0) + ' = i * ' + (bytesPerElement / size).toFixed(0) + ';\n'; + } + for (var c = 0; c < member.components; c++) { + var argName = 'v' + argNames.length; + var index = 'o' + size.toFixed(0) + ' + ' + (member.offset / size + c).toFixed(0); + body += 'this.' + getArrayViewName(member.type) + '[' + index + '] = ' + argName + ';\n'; + argNames.push(argName); + } + } + body += 'return i;'; + return new Function(argNames, body); +} +function createMemberComponentString(member, component) { + var elementOffset = 'this._pos' + sizeOf(member.type).toFixed(0); + var componentOffset = (member.offset / sizeOf(member.type) + component).toFixed(0); + var index = elementOffset + ' + ' + componentOffset; + return 'this._structArray.' + getArrayViewName(member.type) + '[' + index + ']'; +} +function createGetter(member, c) { + return new Function([], 'return ' + createMemberComponentString(member, c) + ';'); +} +function createSetter(member, c) { + return new Function(['x'], createMemberComponentString(member, c) + ' = x;'); +} +function Struct(structArray, index) { + this._structArray = structArray; + this._pos1 = index * this.size; + this._pos2 = this._pos1 / 2; + this._pos4 = this._pos1 / 4; + this._pos8 = this._pos1 / 8; +} +function StructArray(serialized) { + if (serialized !== undefined) { + this.arrayBuffer = serialized.arrayBuffer; + this.length = serialized.length; + this.capacity = this.arrayBuffer.byteLength / this.bytesPerElement; + this._refreshViews(); + } else { + this.capacity = -1; + this.resize(0); + } +} +StructArray.prototype.DEFAULT_CAPACITY = 128; +StructArray.prototype.RESIZE_MULTIPLIER = 5; +StructArray.prototype.serialize = function () { + this.trim(); + return { + length: this.length, + arrayBuffer: this.arrayBuffer }; -})(); - -/** - * Returns a string representation of a vector - * - * @param {vec2} vec vector to represent as a string - * @returns {String} string representation of the vector - */ -vec2.str = function (a) { - return 'vec2(' + a[0] + ', ' + a[1] + ')'; }; - -module.exports = vec2; - -},{"./common.js":124}],131:[function(require,module,exports){ -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -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. */ - -var glMatrix = require("./common.js"); - -/** - * @class 3 Dimensional Vector - * @name vec3 - */ -var vec3 = {}; - -/** - * Creates a new, empty vec3 - * - * @returns {vec3} a new 3D vector - */ -vec3.create = function() { - var out = new glMatrix.ARRAY_TYPE(3); - out[0] = 0; - out[1] = 0; - out[2] = 0; - return out; +StructArray.prototype.get = function (index) { + return new this.StructType(this, index); }; - -/** - * Creates a new vec3 initialized with values from an existing vector - * - * @param {vec3} a vector to clone - * @returns {vec3} a new 3D vector - */ -vec3.clone = function(a) { - var out = new glMatrix.ARRAY_TYPE(3); - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - return out; +StructArray.prototype.trim = function () { + if (this.length !== this.capacity) { + this.capacity = this.length; + this.arrayBuffer = this.arrayBuffer.slice(0, this.length * this.bytesPerElement); + this._refreshViews(); + } }; - -/** - * Creates a new vec3 initialized with the given values - * - * @param {Number} x X component - * @param {Number} y Y component - * @param {Number} z Z component - * @returns {vec3} a new 3D vector - */ -vec3.fromValues = function(x, y, z) { - var out = new glMatrix.ARRAY_TYPE(3); - out[0] = x; - out[1] = y; - out[2] = z; - return out; +StructArray.prototype.resize = function (n) { + this.length = n; + if (n > this.capacity) { + this.capacity = Math.max(n, Math.floor(this.capacity * this.RESIZE_MULTIPLIER), this.DEFAULT_CAPACITY); + this.arrayBuffer = new ArrayBuffer(this.capacity * this.bytesPerElement); + var oldUint8Array = this.uint8; + this._refreshViews(); + if (oldUint8Array) + this.uint8.set(oldUint8Array); + } }; - -/** - * Copy the values from one vec3 to another - * - * @param {vec3} out the receiving vector - * @param {vec3} a the source vector - * @returns {vec3} out - */ -vec3.copy = function(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - return out; +StructArray.prototype._refreshViews = function () { + for (var t = 0; t < this._usedTypes.length; t++) { + var type = this._usedTypes[t]; + this[getArrayViewName(type)] = new viewTypes[type](this.arrayBuffer); + } }; - -/** - * Set the components of a vec3 to the given values - * - * @param {vec3} out the receiving vector - * @param {Number} x X component - * @param {Number} y Y component - * @param {Number} z Z component - * @returns {vec3} out - */ -vec3.set = function(out, x, y, z) { - out[0] = x; - out[1] = y; - out[2] = z; - return out; +StructArray.prototype.toArray = function (startIndex, endIndex) { + var array = []; + for (var i = startIndex; i < endIndex; i++) { + var struct = this.get(i); + array.push(struct); + } + return array; }; - -/** - * Adds two vec3's - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {vec3} out - */ -vec3.add = function(out, a, b) { - out[0] = a[0] + b[0]; - out[1] = a[1] + b[1]; - out[2] = a[2] + b[2]; - return out; +},{}],187:[function(require,module,exports){ +'use strict'; +module.exports = resolveTokens; +function resolveTokens(properties, text) { + return text.replace(/{([^{}]+)}/g, function (match, key) { + return key in properties ? properties[key] : ''; + }); +} +},{}],188:[function(require,module,exports){ +'use strict'; +var UnitBezier = require('unitbezier'); +var Coordinate = require('../geo/coordinate'); +exports.easeCubicInOut = function (t) { + if (t <= 0) + return 0; + if (t >= 1) + return 1; + var t2 = t * t, t3 = t2 * t; + return 4 * (t < 0.5 ? t3 : 3 * (t - t2) + t3 - 0.75); }; - -/** - * Subtracts vector b from vector a - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {vec3} out - */ -vec3.subtract = function(out, a, b) { - out[0] = a[0] - b[0]; - out[1] = a[1] - b[1]; - out[2] = a[2] - b[2]; - return out; +exports.bezier = function (p1x, p1y, p2x, p2y) { + var bezier = new UnitBezier(p1x, p1y, p2x, p2y); + return function (t) { + return bezier.solve(t); + }; }; - -/** - * Alias for {@link vec3.subtract} - * @function - */ -vec3.sub = vec3.subtract; - -/** - * Multiplies two vec3's - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {vec3} out - */ -vec3.multiply = function(out, a, b) { - out[0] = a[0] * b[0]; - out[1] = a[1] * b[1]; - out[2] = a[2] * b[2]; - return out; +exports.ease = exports.bezier(0.25, 0.1, 0.25, 1); +exports.clamp = function (n, min, max) { + return Math.min(max, Math.max(min, n)); }; - -/** - * Alias for {@link vec3.multiply} - * @function - */ -vec3.mul = vec3.multiply; - -/** - * Divides two vec3's - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {vec3} out - */ -vec3.divide = function(out, a, b) { - out[0] = a[0] / b[0]; - out[1] = a[1] / b[1]; - out[2] = a[2] / b[2]; - return out; +exports.wrap = function (n, min, max) { + var d = max - min; + var w = ((n - min) % d + d) % d + min; + return w === min ? max : w; }; - -/** - * Alias for {@link vec3.divide} - * @function - */ -vec3.div = vec3.divide; - -/** - * Returns the minimum of two vec3's - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {vec3} out - */ -vec3.min = function(out, a, b) { - out[0] = Math.min(a[0], b[0]); - out[1] = Math.min(a[1], b[1]); - out[2] = Math.min(a[2], b[2]); - return out; +exports.coalesce = function () { + for (var i = 0; i < arguments.length; i++) { + var arg = arguments[i]; + if (arg !== null && arg !== undefined) + return arg; + } }; - -/** - * Returns the maximum of two vec3's - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {vec3} out - */ -vec3.max = function(out, a, b) { - out[0] = Math.max(a[0], b[0]); - out[1] = Math.max(a[1], b[1]); - out[2] = Math.max(a[2], b[2]); - return out; +exports.asyncAll = function (array, fn, callback) { + if (!array.length) { + return callback(null, []); + } + var remaining = array.length; + var results = new Array(array.length); + var error = null; + array.forEach(function (item, i) { + fn(item, function (err, result) { + if (err) + error = err; + results[i] = result; + if (--remaining === 0) + callback(error, results); + }); + }); }; - -/** - * Scales a vec3 by a scalar number - * - * @param {vec3} out the receiving vector - * @param {vec3} a the vector to scale - * @param {Number} b amount to scale the vector by - * @returns {vec3} out - */ -vec3.scale = function(out, a, b) { - out[0] = a[0] * b; - out[1] = a[1] * b; - out[2] = a[2] * b; - return out; +exports.keysDifference = function (obj, other) { + var difference = []; + for (var i in obj) { + if (!(i in other)) { + difference.push(i); + } + } + return difference; }; - -/** - * Adds two vec3's after scaling the second operand by a scalar value - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @param {Number} scale the amount to scale b by before adding - * @returns {vec3} out - */ -vec3.scaleAndAdd = function(out, a, b, scale) { - out[0] = a[0] + (b[0] * scale); - out[1] = a[1] + (b[1] * scale); - out[2] = a[2] + (b[2] * scale); - return out; +exports.extend = function (dest) { + for (var i = 1; i < arguments.length; i++) { + var src = arguments[i]; + for (var k in src) { + dest[k] = src[k]; + } + } + return dest; }; - -/** - * Calculates the euclidian distance between two vec3's - * - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {Number} distance between a and b - */ -vec3.distance = function(a, b) { - var x = b[0] - a[0], - y = b[1] - a[1], - z = b[2] - a[2]; - return Math.sqrt(x*x + y*y + z*z); +exports.extendAll = function (dest, src) { + for (var i in src) { + Object.defineProperty(dest, i, Object.getOwnPropertyDescriptor(src, i)); + } + return dest; +}; +exports.inherit = function (parent, props) { + var parentProto = typeof parent === 'function' ? parent.prototype : parent, proto = Object.create(parentProto); + exports.extendAll(proto, props); + return proto; }; - -/** - * Alias for {@link vec3.distance} - * @function - */ -vec3.dist = vec3.distance; - -/** - * Calculates the squared euclidian distance between two vec3's - * - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {Number} squared distance between a and b - */ -vec3.squaredDistance = function(a, b) { - var x = b[0] - a[0], - y = b[1] - a[1], - z = b[2] - a[2]; - return x*x + y*y + z*z; +exports.pick = function (src, properties) { + var result = {}; + for (var i = 0; i < properties.length; i++) { + var k = properties[i]; + if (k in src) { + result[k] = src[k]; + } + } + return result; }; - -/** - * Alias for {@link vec3.squaredDistance} - * @function - */ -vec3.sqrDist = vec3.squaredDistance; - -/** - * Calculates the length of a vec3 - * - * @param {vec3} a vector to calculate length of - * @returns {Number} length of a - */ -vec3.length = function (a) { - var x = a[0], - y = a[1], - z = a[2]; - return Math.sqrt(x*x + y*y + z*z); +var id = 1; +exports.uniqueId = function () { + return id++; }; - -/** - * Alias for {@link vec3.length} - * @function - */ -vec3.len = vec3.length; - -/** - * Calculates the squared length of a vec3 - * - * @param {vec3} a vector to calculate squared length of - * @returns {Number} squared length of a - */ -vec3.squaredLength = function (a) { - var x = a[0], - y = a[1], - z = a[2]; - return x*x + y*y + z*z; +exports.debounce = function (fn, time) { + var timer, args; + return function () { + args = arguments; + clearTimeout(timer); + timer = setTimeout(function () { + fn.apply(null, args); + }, time); + }; }; - -/** - * Alias for {@link vec3.squaredLength} - * @function - */ -vec3.sqrLen = vec3.squaredLength; - -/** - * Negates the components of a vec3 - * - * @param {vec3} out the receiving vector - * @param {vec3} a vector to negate - * @returns {vec3} out - */ -vec3.negate = function(out, a) { - out[0] = -a[0]; - out[1] = -a[1]; - out[2] = -a[2]; - return out; +exports.bindAll = function (fns, context) { + fns.forEach(function (fn) { + if (!context[fn]) { + return; + } + context[fn] = context[fn].bind(context); + }); }; - -/** - * Returns the inverse of the components of a vec3 - * - * @param {vec3} out the receiving vector - * @param {vec3} a vector to invert - * @returns {vec3} out - */ -vec3.inverse = function(out, a) { - out[0] = 1.0 / a[0]; - out[1] = 1.0 / a[1]; - out[2] = 1.0 / a[2]; - return out; +exports.bindHandlers = function (context) { + for (var i in context) { + if (typeof context[i] === 'function' && i.indexOf('_on') === 0) { + context[i] = context[i].bind(context); + } + } }; - -/** - * Normalize a vec3 - * - * @param {vec3} out the receiving vector - * @param {vec3} a vector to normalize - * @returns {vec3} out - */ -vec3.normalize = function(out, a) { - var x = a[0], - y = a[1], - z = a[2]; - var len = x*x + y*y + z*z; - if (len > 0) { - //TODO: evaluate use of glm_invsqrt here? - len = 1 / Math.sqrt(len); - out[0] = a[0] * len; - out[1] = a[1] * len; - out[2] = a[2] * len; +exports.setOptions = function (obj, options) { + if (!obj.hasOwnProperty('options')) { + obj.options = obj.options ? Object.create(obj.options) : {}; } - return out; + for (var i in options) { + obj.options[i] = options[i]; + } + return obj.options; }; - -/** - * Calculates the dot product of two vec3's - * - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {Number} dot product of a and b - */ -vec3.dot = function (a, b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +exports.getCoordinatesCenter = function (coords) { + var minX = Infinity; + var minY = Infinity; + var maxX = -Infinity; + var maxY = -Infinity; + for (var i = 0; i < coords.length; i++) { + minX = Math.min(minX, coords[i].column); + minY = Math.min(minY, coords[i].row); + maxX = Math.max(maxX, coords[i].column); + maxY = Math.max(maxY, coords[i].row); + } + var dx = maxX - minX; + var dy = maxY - minY; + var dMax = Math.max(dx, dy); + return new Coordinate((minX + maxX) / 2, (minY + maxY) / 2, 0).zoomTo(Math.floor(-Math.log(dMax) / Math.LN2)); }; - -/** - * Computes the cross product of two vec3's - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {vec3} out - */ -vec3.cross = function(out, a, b) { - var ax = a[0], ay = a[1], az = a[2], - bx = b[0], by = b[1], bz = b[2]; - - out[0] = ay * bz - az * by; - out[1] = az * bx - ax * bz; - out[2] = ax * by - ay * bx; - return out; +exports.endsWith = function (string, suffix) { + return string.indexOf(suffix, string.length - suffix.length) !== -1; }; - -/** - * Performs a linear interpolation between two vec3's - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @param {Number} t interpolation amount between the two inputs - * @returns {vec3} out - */ -vec3.lerp = function (out, a, b, t) { - var ax = a[0], - ay = a[1], - az = a[2]; - out[0] = ax + t * (b[0] - ax); - out[1] = ay + t * (b[1] - ay); - out[2] = az + t * (b[2] - az); - return out; +exports.startsWith = function (string, prefix) { + return string.indexOf(prefix) === 0; }; - -/** - * Performs a hermite interpolation with two control points - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @param {vec3} c the third operand - * @param {vec3} d the fourth operand - * @param {Number} t interpolation amount between the two inputs - * @returns {vec3} out - */ -vec3.hermite = function (out, a, b, c, d, t) { - var factorTimes2 = t * t, - factor1 = factorTimes2 * (2 * t - 3) + 1, - factor2 = factorTimes2 * (t - 2) + t, - factor3 = factorTimes2 * (t - 1), - factor4 = factorTimes2 * (3 - 2 * t); - - out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4; - out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4; - out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4; - - return out; +exports.mapObject = function (input, iterator, context) { + var output = {}; + for (var key in input) { + output[key] = iterator.call(context || this, input[key], key, input); + } + return output; +}; +exports.filterObject = function (input, iterator, context) { + var output = {}; + for (var key in input) { + if (iterator.call(context || this, input[key], key, input)) { + output[key] = input[key]; + } + } + return output; +}; +exports.deepEqual = function (a, b) { + if (Array.isArray(a)) { + if (!Array.isArray(b) || a.length !== b.length) + return false; + for (var i = 0; i < a.length; i++) { + if (!exports.deepEqual(a[i], b[i])) + return false; + } + return true; + } + if (typeof a === 'object' && a !== null && b !== null) { + if (!(typeof b === 'object')) + return false; + var keys = Object.keys(a); + if (keys.length !== Object.keys(b).length) + return false; + for (var key in a) { + if (!exports.deepEqual(a[key], b[key])) + return false; + } + return true; + } + return a === b; +}; +exports.clone = function (input) { + if (Array.isArray(input)) { + return input.map(exports.clone); + } else if (typeof input === 'object') { + return exports.mapObject(input, exports.clone); + } else { + return input; + } }; - -/** - * Performs a bezier interpolation with two control points - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @param {vec3} c the third operand - * @param {vec3} d the fourth operand - * @param {Number} t interpolation amount between the two inputs - * @returns {vec3} out - */ -vec3.bezier = function (out, a, b, c, d, t) { - var inverseFactor = 1 - t, - inverseFactorTimesTwo = inverseFactor * inverseFactor, - factorTimes2 = t * t, - factor1 = inverseFactorTimesTwo * inverseFactor, - factor2 = 3 * t * inverseFactorTimesTwo, - factor3 = 3 * factorTimes2 * inverseFactor, - factor4 = factorTimes2 * t; - - out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4; - out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4; - out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4; - - return out; +exports.arraysIntersect = function (a, b) { + for (var l = 0; l < a.length; l++) { + if (b.indexOf(a[l]) >= 0) + return true; + } + return false; }; - -/** - * Generates a random vector with the given scale - * - * @param {vec3} out the receiving vector - * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned - * @returns {vec3} out - */ -vec3.random = function (out, scale) { - scale = scale || 1.0; - - var r = glMatrix.RANDOM() * 2.0 * Math.PI; - var z = (glMatrix.RANDOM() * 2.0) - 1.0; - var zScale = Math.sqrt(1.0-z*z) * scale; - - out[0] = Math.cos(r) * zScale; - out[1] = Math.sin(r) * zScale; - out[2] = z * scale; - return out; +var warnOnceHistory = {}; +exports.warnOnce = function (message) { + if (!warnOnceHistory[message]) { + if (typeof console !== 'undefined') + console.warn(message); + warnOnceHistory[message] = true; + } }; - -/** - * Transforms the vec3 with a mat4. - * 4th vector component is implicitly '1' - * - * @param {vec3} out the receiving vector - * @param {vec3} a the vector to transform - * @param {mat4} m matrix to transform with - * @returns {vec3} out - */ -vec3.transformMat4 = function(out, a, m) { - var x = a[0], y = a[1], z = a[2], - w = m[3] * x + m[7] * y + m[11] * z + m[15]; - w = w || 1.0; - out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w; - out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w; - out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w; - return out; +exports.isCounterClockwise = function (a, b, c) { + return (c.y - a.y) * (b.x - a.x) > (b.y - a.y) * (c.x - a.x); }; - -/** - * Transforms the vec3 with a mat3. - * - * @param {vec3} out the receiving vector - * @param {vec3} a the vector to transform - * @param {mat4} m the 3x3 matrix to transform with - * @returns {vec3} out - */ -vec3.transformMat3 = function(out, a, m) { - var x = a[0], y = a[1], z = a[2]; - out[0] = x * m[0] + y * m[3] + z * m[6]; - out[1] = x * m[1] + y * m[4] + z * m[7]; - out[2] = x * m[2] + y * m[5] + z * m[8]; - return out; +exports.calculateSignedArea = function (ring) { + var sum = 0; + for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) { + p1 = ring[i]; + p2 = ring[j]; + sum += (p2.x - p1.x) * (p1.y + p2.y); + } + return sum; }; - -/** - * Transforms the vec3 with a quat - * - * @param {vec3} out the receiving vector - * @param {vec3} a the vector to transform - * @param {quat} q quaternion to transform with - * @returns {vec3} out - */ -vec3.transformQuat = function(out, a, q) { - // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations - - var x = a[0], y = a[1], z = a[2], - qx = q[0], qy = q[1], qz = q[2], qw = q[3], - - // calculate quat * vec - ix = qw * x + qy * z - qz * y, - iy = qw * y + qz * x - qx * z, - iz = qw * z + qx * y - qy * x, - iw = -qx * x - qy * y - qz * z; - - // calculate result * inverse quat - out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; - out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; - out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; - return out; +exports.isClosedPolygon = function (points) { + if (points.length < 4) + return false; + var p1 = points[0]; + var p2 = points[points.length - 1]; + if (Math.abs(p1.x - p2.x) > 0 || Math.abs(p1.y - p2.y) > 0) { + return false; + } + return Math.abs(exports.calculateSignedArea(points)) > 0.01; +}; +},{"../geo/coordinate":81,"unitbezier":206}],189:[function(require,module,exports){ +'use strict'; +module.exports = Feature; +function Feature(vectorTileFeature, z, x, y) { + this._vectorTileFeature = vectorTileFeature; + vectorTileFeature._z = z; + vectorTileFeature._x = x; + vectorTileFeature._y = y; + this.properties = vectorTileFeature.properties; + if (vectorTileFeature.id != null) { + this.id = vectorTileFeature.id; + } +} +Feature.prototype = { + type: 'Feature', + get geometry() { + if (this._geometry === undefined) { + this._geometry = this._vectorTileFeature.toGeoJSON(this._vectorTileFeature._x, this._vectorTileFeature._y, this._vectorTileFeature._z).geometry; + } + return this._geometry; + }, + set geometry(g) { + this._geometry = g; + }, + toJSON: function () { + var json = {}; + for (var i in this) { + if (i === '_geometry' || i === '_vectorTileFeature' || i === 'toJSON') + continue; + json[i] = this[i]; + } + return json; + } +}; +},{}],190:[function(require,module,exports){ +'use strict'; +var WebWorker = require('./web_worker'); +module.exports = WorkerPool; +function WorkerPool() { + this.active = {}; +} +WorkerPool.prototype = { + acquire: function (mapId) { + if (!this.workers) { + var workerCount = require('../mapbox-gl').workerCount; + this.workers = []; + while (this.workers.length < workerCount) { + this.workers.push(new WebWorker()); + } + } + this.active[mapId] = true; + return this.workers.slice(); + }, + release: function (mapId) { + delete this.active[mapId]; + if (Object.keys(this.active).length === 0) { + this.workers.forEach(function (w) { + w.terminate(); + }); + this.workers = null; + } + } }; +},{"../mapbox-gl":87,"./web_worker":172}],191:[function(require,module,exports){ +'use strict'; -/** - * Rotate a 3D vector around the x-axis - * @param {vec3} out The receiving vec3 - * @param {vec3} a The vec3 point to rotate - * @param {vec3} b The origin of the rotation - * @param {Number} c The angle of rotation - * @returns {vec3} out - */ -vec3.rotateX = function(out, a, b, c){ - var p = [], r=[]; - //Translate point to the origin - p[0] = a[0] - b[0]; - p[1] = a[1] - b[1]; - p[2] = a[2] - b[2]; +// lightweight Buffer shim for pbf browser build +// based on code from github.com/feross/buffer (MIT-licensed) - //perform rotation - r[0] = p[0]; - r[1] = p[1]*Math.cos(c) - p[2]*Math.sin(c); - r[2] = p[1]*Math.sin(c) + p[2]*Math.cos(c); +module.exports = Buffer; - //translate to correct position - out[0] = r[0] + b[0]; - out[1] = r[1] + b[1]; - out[2] = r[2] + b[2]; +var ieee754 = require('ieee754'); - return out; -}; +var BufferMethods; -/** - * Rotate a 3D vector around the y-axis - * @param {vec3} out The receiving vec3 - * @param {vec3} a The vec3 point to rotate - * @param {vec3} b The origin of the rotation - * @param {Number} c The angle of rotation - * @returns {vec3} out - */ -vec3.rotateY = function(out, a, b, c){ - var p = [], r=[]; - //Translate point to the origin - p[0] = a[0] - b[0]; - p[1] = a[1] - b[1]; - p[2] = a[2] - b[2]; - - //perform rotation - r[0] = p[2]*Math.sin(c) + p[0]*Math.cos(c); - r[1] = p[1]; - r[2] = p[2]*Math.cos(c) - p[0]*Math.sin(c); - - //translate to correct position - out[0] = r[0] + b[0]; - out[1] = r[1] + b[1]; - out[2] = r[2] + b[2]; - - return out; -}; +function Buffer(length) { + var arr; + if (length && length.length) { + arr = length; + length = arr.length; + } + var buf = new Uint8Array(length || 0); + if (arr) buf.set(arr); -/** - * Rotate a 3D vector around the z-axis - * @param {vec3} out The receiving vec3 - * @param {vec3} a The vec3 point to rotate - * @param {vec3} b The origin of the rotation - * @param {Number} c The angle of rotation - * @returns {vec3} out - */ -vec3.rotateZ = function(out, a, b, c){ - var p = [], r=[]; - //Translate point to the origin - p[0] = a[0] - b[0]; - p[1] = a[1] - b[1]; - p[2] = a[2] - b[2]; - - //perform rotation - r[0] = p[0]*Math.cos(c) - p[1]*Math.sin(c); - r[1] = p[0]*Math.sin(c) + p[1]*Math.cos(c); - r[2] = p[2]; - - //translate to correct position - out[0] = r[0] + b[0]; - out[1] = r[1] + b[1]; - out[2] = r[2] + b[2]; - - return out; -}; + buf.readUInt32LE = BufferMethods.readUInt32LE; + buf.writeUInt32LE = BufferMethods.writeUInt32LE; + buf.readInt32LE = BufferMethods.readInt32LE; + buf.writeInt32LE = BufferMethods.writeInt32LE; + buf.readFloatLE = BufferMethods.readFloatLE; + buf.writeFloatLE = BufferMethods.writeFloatLE; + buf.readDoubleLE = BufferMethods.readDoubleLE; + buf.writeDoubleLE = BufferMethods.writeDoubleLE; + buf.toString = BufferMethods.toString; + buf.write = BufferMethods.write; + buf.slice = BufferMethods.slice; + buf.copy = BufferMethods.copy; -/** - * Perform some operation over an array of vec3s. - * - * @param {Array} a the array of vectors to iterate over - * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed - * @param {Number} offset Number of elements to skip at the beginning of the array - * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array - * @param {Function} fn Function to call for each vector in the array - * @param {Object} [arg] additional argument to pass to fn - * @returns {Array} a - * @function - */ -vec3.forEach = (function() { - var vec = vec3.create(); + buf._isBuffer = true; + return buf; +} - return function(a, stride, offset, count, fn, arg) { - var i, l; - if(!stride) { - stride = 3; - } +var lastStr, lastStrEncoded; - if(!offset) { - offset = 0; - } - - if(count) { - l = Math.min((count * stride) + offset, a.length); - } else { - l = a.length; - } +BufferMethods = { + readUInt32LE: function(pos) { + return ((this[pos]) | + (this[pos + 1] << 8) | + (this[pos + 2] << 16)) + + (this[pos + 3] * 0x1000000); + }, - for(i = offset; i < l; i += stride) { - vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; - fn(vec, vec, arg); - a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; - } - - return a; - }; -})(); + writeUInt32LE: function(val, pos) { + this[pos] = val; + this[pos + 1] = (val >>> 8); + this[pos + 2] = (val >>> 16); + this[pos + 3] = (val >>> 24); + }, -/** - * Get the angle between two 3D vectors - * @param {vec3} a The first operand - * @param {vec3} b The second operand - * @returns {Number} The angle in radians - */ -vec3.angle = function(a, b) { - - var tempA = vec3.fromValues(a[0], a[1], a[2]); - var tempB = vec3.fromValues(b[0], b[1], b[2]); - - vec3.normalize(tempA, tempA); - vec3.normalize(tempB, tempB); - - var cosine = vec3.dot(tempA, tempB); + readInt32LE: function(pos) { + return ((this[pos]) | + (this[pos + 1] << 8) | + (this[pos + 2] << 16)) + + (this[pos + 3] << 24); + }, - if(cosine > 1.0){ - return 0; - } else { - return Math.acos(cosine); - } -}; + readFloatLE: function(pos) { return ieee754.read(this, pos, true, 23, 4); }, + readDoubleLE: function(pos) { return ieee754.read(this, pos, true, 52, 8); }, -/** - * Returns a string representation of a vector - * - * @param {vec3} vec vector to represent as a string - * @returns {String} string representation of the vector - */ -vec3.str = function (a) { - return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')'; -}; + writeFloatLE: function(val, pos) { return ieee754.write(this, val, pos, true, 23, 4); }, + writeDoubleLE: function(val, pos) { return ieee754.write(this, val, pos, true, 52, 8); }, -module.exports = vec3; + toString: function(encoding, start, end) { + var str = '', + tmp = ''; -},{"./common.js":124}],132:[function(require,module,exports){ -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. + start = start || 0; + end = Math.min(this.length, end || this.length); -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: + for (var i = start; i < end; i++) { + var ch = this[i]; + if (ch <= 0x7F) { + str += decodeURIComponent(tmp) + String.fromCharCode(ch); + tmp = ''; + } else { + tmp += '%' + ch.toString(16); + } + } -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. + str += decodeURIComponent(tmp); -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. */ + return str; + }, -var glMatrix = require("./common.js"); + write: function(str, pos) { + var bytes = str === lastStr ? lastStrEncoded : encodeString(str); + for (var i = 0; i < bytes.length; i++) { + this[pos + i] = bytes[i]; + } + }, -/** - * @class 4 Dimensional Vector - * @name vec4 - */ -var vec4 = {}; + slice: function(start, end) { + return this.subarray(start, end); + }, -/** - * Creates a new, empty vec4 - * - * @returns {vec4} a new 4D vector - */ -vec4.create = function() { - var out = new glMatrix.ARRAY_TYPE(4); - out[0] = 0; - out[1] = 0; - out[2] = 0; - out[3] = 0; - return out; + copy: function(buf, pos) { + pos = pos || 0; + for (var i = 0; i < this.length; i++) { + buf[pos + i] = this[i]; + } + } }; -/** - * Creates a new vec4 initialized with values from an existing vector - * - * @param {vec4} a vector to clone - * @returns {vec4} a new 4D vector - */ -vec4.clone = function(a) { - var out = new glMatrix.ARRAY_TYPE(4); - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - return out; -}; +BufferMethods.writeInt32LE = BufferMethods.writeUInt32LE; -/** - * Creates a new vec4 initialized with the given values - * - * @param {Number} x X component - * @param {Number} y Y component - * @param {Number} z Z component - * @param {Number} w W component - * @returns {vec4} a new 4D vector - */ -vec4.fromValues = function(x, y, z, w) { - var out = new glMatrix.ARRAY_TYPE(4); - out[0] = x; - out[1] = y; - out[2] = z; - out[3] = w; - return out; +Buffer.byteLength = function(str) { + lastStr = str; + lastStrEncoded = encodeString(str); + return lastStrEncoded.length; }; -/** - * Copy the values from one vec4 to another - * - * @param {vec4} out the receiving vector - * @param {vec4} a the source vector - * @returns {vec4} out - */ -vec4.copy = function(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - return out; +Buffer.isBuffer = function(buf) { + return !!(buf && buf._isBuffer); }; -/** - * Set the components of a vec4 to the given values - * - * @param {vec4} out the receiving vector - * @param {Number} x X component - * @param {Number} y Y component - * @param {Number} z Z component - * @param {Number} w W component - * @returns {vec4} out - */ -vec4.set = function(out, x, y, z, w) { - out[0] = x; - out[1] = y; - out[2] = z; - out[3] = w; - return out; -}; +function encodeString(str) { + var length = str.length, + bytes = []; -/** - * Adds two vec4's - * - * @param {vec4} out the receiving vector - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @returns {vec4} out - */ -vec4.add = function(out, a, b) { - out[0] = a[0] + b[0]; - out[1] = a[1] + b[1]; - out[2] = a[2] + b[2]; - out[3] = a[3] + b[3]; - return out; -}; + for (var i = 0, c, lead; i < length; i++) { + c = str.charCodeAt(i); // code point + + if (c > 0xD7FF && c < 0xE000) { + + if (lead) { + if (c < 0xDC00) { + bytes.push(0xEF, 0xBF, 0xBD); + lead = c; + continue; + + } else { + c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000; + lead = null; + } + + } else { + if (c > 0xDBFF || (i + 1 === length)) bytes.push(0xEF, 0xBF, 0xBD); + else lead = c; + + continue; + } + + } else if (lead) { + bytes.push(0xEF, 0xBF, 0xBD); + lead = null; + } + + if (c < 0x80) bytes.push(c); + else if (c < 0x800) bytes.push(c >> 0x6 | 0xC0, c & 0x3F | 0x80); + else if (c < 0x10000) bytes.push(c >> 0xC | 0xE0, c >> 0x6 & 0x3F | 0x80, c & 0x3F | 0x80); + else bytes.push(c >> 0x12 | 0xF0, c >> 0xC & 0x3F | 0x80, c >> 0x6 & 0x3F | 0x80, c & 0x3F | 0x80); + } + return bytes; +} -/** - * Subtracts vector b from vector a - * - * @param {vec4} out the receiving vector - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @returns {vec4} out - */ -vec4.subtract = function(out, a, b) { - out[0] = a[0] - b[0]; - out[1] = a[1] - b[1]; - out[2] = a[2] - b[2]; - out[3] = a[3] - b[3]; - return out; -}; +},{"ieee754":40}],192:[function(require,module,exports){ +(function (global){ +'use strict'; -/** - * Alias for {@link vec4.subtract} - * @function - */ -vec4.sub = vec4.subtract; +module.exports = Pbf; -/** - * Multiplies two vec4's - * - * @param {vec4} out the receiving vector - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @returns {vec4} out - */ -vec4.multiply = function(out, a, b) { - out[0] = a[0] * b[0]; - out[1] = a[1] * b[1]; - out[2] = a[2] * b[2]; - out[3] = a[3] * b[3]; - return out; -}; +var Buffer = global.Buffer || require('./buffer'); -/** - * Alias for {@link vec4.multiply} - * @function - */ -vec4.mul = vec4.multiply; +function Pbf(buf) { + this.buf = !Buffer.isBuffer(buf) ? new Buffer(buf || 0) : buf; + this.pos = 0; + this.length = this.buf.length; +} -/** - * Divides two vec4's - * - * @param {vec4} out the receiving vector - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @returns {vec4} out - */ -vec4.divide = function(out, a, b) { - out[0] = a[0] / b[0]; - out[1] = a[1] / b[1]; - out[2] = a[2] / b[2]; - out[3] = a[3] / b[3]; - return out; -}; +Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum +Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64 +Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields +Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32 -/** - * Alias for {@link vec4.divide} - * @function - */ -vec4.div = vec4.divide; +var SHIFT_LEFT_32 = (1 << 16) * (1 << 16), + SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32, + POW_2_63 = Math.pow(2, 63); -/** - * Returns the minimum of two vec4's - * - * @param {vec4} out the receiving vector - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @returns {vec4} out - */ -vec4.min = function(out, a, b) { - out[0] = Math.min(a[0], b[0]); - out[1] = Math.min(a[1], b[1]); - out[2] = Math.min(a[2], b[2]); - out[3] = Math.min(a[3], b[3]); - return out; -}; +Pbf.prototype = { -/** - * Returns the maximum of two vec4's - * - * @param {vec4} out the receiving vector - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @returns {vec4} out - */ -vec4.max = function(out, a, b) { - out[0] = Math.max(a[0], b[0]); - out[1] = Math.max(a[1], b[1]); - out[2] = Math.max(a[2], b[2]); - out[3] = Math.max(a[3], b[3]); - return out; -}; + destroy: function() { + this.buf = null; + }, -/** - * Scales a vec4 by a scalar number - * - * @param {vec4} out the receiving vector - * @param {vec4} a the vector to scale - * @param {Number} b amount to scale the vector by - * @returns {vec4} out - */ -vec4.scale = function(out, a, b) { - out[0] = a[0] * b; - out[1] = a[1] * b; - out[2] = a[2] * b; - out[3] = a[3] * b; - return out; -}; + // === READING ================================================================= -/** - * Adds two vec4's after scaling the second operand by a scalar value - * - * @param {vec4} out the receiving vector - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @param {Number} scale the amount to scale b by before adding - * @returns {vec4} out - */ -vec4.scaleAndAdd = function(out, a, b, scale) { - out[0] = a[0] + (b[0] * scale); - out[1] = a[1] + (b[1] * scale); - out[2] = a[2] + (b[2] * scale); - out[3] = a[3] + (b[3] * scale); - return out; -}; + readFields: function(readField, result, end) { + end = end || this.length; -/** - * Calculates the euclidian distance between two vec4's - * - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @returns {Number} distance between a and b - */ -vec4.distance = function(a, b) { - var x = b[0] - a[0], - y = b[1] - a[1], - z = b[2] - a[2], - w = b[3] - a[3]; - return Math.sqrt(x*x + y*y + z*z + w*w); -}; + while (this.pos < end) { + var val = this.readVarint(), + tag = val >> 3, + startPos = this.pos; -/** - * Alias for {@link vec4.distance} - * @function - */ -vec4.dist = vec4.distance; + readField(tag, result, this); -/** - * Calculates the squared euclidian distance between two vec4's - * - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @returns {Number} squared distance between a and b - */ -vec4.squaredDistance = function(a, b) { - var x = b[0] - a[0], - y = b[1] - a[1], - z = b[2] - a[2], - w = b[3] - a[3]; - return x*x + y*y + z*z + w*w; -}; + if (this.pos === startPos) this.skip(val); + } + return result; + }, -/** - * Alias for {@link vec4.squaredDistance} - * @function - */ -vec4.sqrDist = vec4.squaredDistance; + readMessage: function(readField, result) { + return this.readFields(readField, result, this.readVarint() + this.pos); + }, -/** - * Calculates the length of a vec4 - * - * @param {vec4} a vector to calculate length of - * @returns {Number} length of a - */ -vec4.length = function (a) { - var x = a[0], - y = a[1], - z = a[2], - w = a[3]; - return Math.sqrt(x*x + y*y + z*z + w*w); -}; + readFixed32: function() { + var val = this.buf.readUInt32LE(this.pos); + this.pos += 4; + return val; + }, -/** - * Alias for {@link vec4.length} - * @function - */ -vec4.len = vec4.length; + readSFixed32: function() { + var val = this.buf.readInt32LE(this.pos); + this.pos += 4; + return val; + }, -/** - * Calculates the squared length of a vec4 - * - * @param {vec4} a vector to calculate squared length of - * @returns {Number} squared length of a - */ -vec4.squaredLength = function (a) { - var x = a[0], - y = a[1], - z = a[2], - w = a[3]; - return x*x + y*y + z*z + w*w; -}; + // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed) + + readFixed64: function() { + var val = this.buf.readUInt32LE(this.pos) + this.buf.readUInt32LE(this.pos + 4) * SHIFT_LEFT_32; + this.pos += 8; + return val; + }, + + readSFixed64: function() { + var val = this.buf.readUInt32LE(this.pos) + this.buf.readInt32LE(this.pos + 4) * SHIFT_LEFT_32; + this.pos += 8; + return val; + }, + + readFloat: function() { + var val = this.buf.readFloatLE(this.pos); + this.pos += 4; + return val; + }, -/** - * Alias for {@link vec4.squaredLength} - * @function - */ -vec4.sqrLen = vec4.squaredLength; + readDouble: function() { + var val = this.buf.readDoubleLE(this.pos); + this.pos += 8; + return val; + }, -/** - * Negates the components of a vec4 - * - * @param {vec4} out the receiving vector - * @param {vec4} a vector to negate - * @returns {vec4} out - */ -vec4.negate = function(out, a) { - out[0] = -a[0]; - out[1] = -a[1]; - out[2] = -a[2]; - out[3] = -a[3]; - return out; -}; + readVarint: function() { + var buf = this.buf, + val, b; -/** - * Returns the inverse of the components of a vec4 - * - * @param {vec4} out the receiving vector - * @param {vec4} a vector to invert - * @returns {vec4} out - */ -vec4.inverse = function(out, a) { - out[0] = 1.0 / a[0]; - out[1] = 1.0 / a[1]; - out[2] = 1.0 / a[2]; - out[3] = 1.0 / a[3]; - return out; -}; + b = buf[this.pos++]; val = b & 0x7f; if (b < 0x80) return val; + b = buf[this.pos++]; val |= (b & 0x7f) << 7; if (b < 0x80) return val; + b = buf[this.pos++]; val |= (b & 0x7f) << 14; if (b < 0x80) return val; + b = buf[this.pos++]; val |= (b & 0x7f) << 21; if (b < 0x80) return val; -/** - * Normalize a vec4 - * - * @param {vec4} out the receiving vector - * @param {vec4} a vector to normalize - * @returns {vec4} out - */ -vec4.normalize = function(out, a) { - var x = a[0], - y = a[1], - z = a[2], - w = a[3]; - var len = x*x + y*y + z*z + w*w; - if (len > 0) { - len = 1 / Math.sqrt(len); - out[0] = x * len; - out[1] = y * len; - out[2] = z * len; - out[3] = w * len; - } - return out; -}; + return readVarintRemainder(val, this); + }, -/** - * Calculates the dot product of two vec4's - * - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @returns {Number} dot product of a and b - */ -vec4.dot = function (a, b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; -}; + readVarint64: function() { + var startPos = this.pos, + val = this.readVarint(); -/** - * Performs a linear interpolation between two vec4's - * - * @param {vec4} out the receiving vector - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @param {Number} t interpolation amount between the two inputs - * @returns {vec4} out - */ -vec4.lerp = function (out, a, b, t) { - var ax = a[0], - ay = a[1], - az = a[2], - aw = a[3]; - out[0] = ax + t * (b[0] - ax); - out[1] = ay + t * (b[1] - ay); - out[2] = az + t * (b[2] - az); - out[3] = aw + t * (b[3] - aw); - return out; -}; + if (val < POW_2_63) return val; -/** - * Generates a random vector with the given scale - * - * @param {vec4} out the receiving vector - * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned - * @returns {vec4} out - */ -vec4.random = function (out, scale) { - scale = scale || 1.0; + var pos = this.pos - 2; + while (this.buf[pos] === 0xff) pos--; + if (pos < startPos) pos = startPos; - //TODO: This is a pretty awful way of doing this. Find something better. - out[0] = glMatrix.RANDOM(); - out[1] = glMatrix.RANDOM(); - out[2] = glMatrix.RANDOM(); - out[3] = glMatrix.RANDOM(); - vec4.normalize(out, out); - vec4.scale(out, out, scale); - return out; -}; + val = 0; + for (var i = 0; i < pos - startPos + 1; i++) { + var b = ~this.buf[startPos + i] & 0x7f; + val += i < 4 ? b << i * 7 : b * Math.pow(2, i * 7); + } -/** - * Transforms the vec4 with a mat4. - * - * @param {vec4} out the receiving vector - * @param {vec4} a the vector to transform - * @param {mat4} m matrix to transform with - * @returns {vec4} out - */ -vec4.transformMat4 = function(out, a, m) { - var x = a[0], y = a[1], z = a[2], w = a[3]; - out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w; - out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w; - out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w; - out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w; - return out; -}; + return -val - 1; + }, -/** - * Transforms the vec4 with a quat - * - * @param {vec4} out the receiving vector - * @param {vec4} a the vector to transform - * @param {quat} q quaternion to transform with - * @returns {vec4} out - */ -vec4.transformQuat = function(out, a, q) { - var x = a[0], y = a[1], z = a[2], - qx = q[0], qy = q[1], qz = q[2], qw = q[3], + readSVarint: function() { + var num = this.readVarint(); + return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding + }, - // calculate quat * vec - ix = qw * x + qy * z - qz * y, - iy = qw * y + qz * x - qx * z, - iz = qw * z + qx * y - qy * x, - iw = -qx * x - qy * y - qz * z; + readBoolean: function() { + return Boolean(this.readVarint()); + }, - // calculate result * inverse quat - out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; - out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; - out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; - out[3] = a[3]; - return out; -}; + readString: function() { + var end = this.readVarint() + this.pos, + str = this.buf.toString('utf8', this.pos, end); + this.pos = end; + return str; + }, -/** - * Perform some operation over an array of vec4s. - * - * @param {Array} a the array of vectors to iterate over - * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed - * @param {Number} offset Number of elements to skip at the beginning of the array - * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array - * @param {Function} fn Function to call for each vector in the array - * @param {Object} [arg] additional argument to pass to fn - * @returns {Array} a - * @function - */ -vec4.forEach = (function() { - var vec = vec4.create(); + readBytes: function() { + var end = this.readVarint() + this.pos, + buffer = this.buf.slice(this.pos, end); + this.pos = end; + return buffer; + }, - return function(a, stride, offset, count, fn, arg) { - var i, l; - if(!stride) { - stride = 4; - } + // verbose for performance reasons; doesn't affect gzipped size - if(!offset) { - offset = 0; - } - - if(count) { - l = Math.min((count * stride) + offset, a.length); - } else { - l = a.length; - } + readPackedVarint: function() { + var end = this.readVarint() + this.pos, arr = []; + while (this.pos < end) arr.push(this.readVarint()); + return arr; + }, + readPackedSVarint: function() { + var end = this.readVarint() + this.pos, arr = []; + while (this.pos < end) arr.push(this.readSVarint()); + return arr; + }, + readPackedBoolean: function() { + var end = this.readVarint() + this.pos, arr = []; + while (this.pos < end) arr.push(this.readBoolean()); + return arr; + }, + readPackedFloat: function() { + var end = this.readVarint() + this.pos, arr = []; + while (this.pos < end) arr.push(this.readFloat()); + return arr; + }, + readPackedDouble: function() { + var end = this.readVarint() + this.pos, arr = []; + while (this.pos < end) arr.push(this.readDouble()); + return arr; + }, + readPackedFixed32: function() { + var end = this.readVarint() + this.pos, arr = []; + while (this.pos < end) arr.push(this.readFixed32()); + return arr; + }, + readPackedSFixed32: function() { + var end = this.readVarint() + this.pos, arr = []; + while (this.pos < end) arr.push(this.readSFixed32()); + return arr; + }, + readPackedFixed64: function() { + var end = this.readVarint() + this.pos, arr = []; + while (this.pos < end) arr.push(this.readFixed64()); + return arr; + }, + readPackedSFixed64: function() { + var end = this.readVarint() + this.pos, arr = []; + while (this.pos < end) arr.push(this.readSFixed64()); + return arr; + }, - for(i = offset; i < l; i += stride) { - vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3]; - fn(vec, vec, arg); - a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3]; - } - - return a; - }; -})(); + skip: function(val) { + var type = val & 0x7; + if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {} + else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos; + else if (type === Pbf.Fixed32) this.pos += 4; + else if (type === Pbf.Fixed64) this.pos += 8; + else throw new Error('Unimplemented type: ' + type); + }, -/** - * Returns a string representation of a vector - * - * @param {vec4} vec vector to represent as a string - * @returns {String} string representation of the vector - */ -vec4.str = function (a) { - return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; -}; + // === WRITING ================================================================= -module.exports = vec4; + writeTag: function(tag, type) { + this.writeVarint((tag << 3) | type); + }, -},{"./common.js":124}],133:[function(require,module,exports){ -'use strict'; + realloc: function(min) { + var length = this.length || 16; -function constant(value) { - return function() { - return value; - } -} + while (length < this.pos + min) length *= 2; -function interpolateNumber(a, b, t) { - return (a * (1 - t)) + (b * t); -} + if (length !== this.length) { + var buf = new Buffer(length); + this.buf.copy(buf); + this.buf = buf; + this.length = length; + } + }, -function interpolateArray(a, b, t) { - var result = []; - for (var i = 0; i < a.length; i++) { - result[i] = interpolateNumber(a[i], b[i], t); - } - return result; -} + finish: function() { + this.length = this.pos; + this.pos = 0; + return this.buf.slice(0, this.length); + }, -exports['interpolated'] = function(f) { - if (!f.stops) { - return constant(f); - } + writeFixed32: function(val) { + this.realloc(4); + this.buf.writeUInt32LE(val, this.pos); + this.pos += 4; + }, - var stops = f.stops, - base = f.base || 1, - interpolate = Array.isArray(stops[0][1]) ? interpolateArray : interpolateNumber; + writeSFixed32: function(val) { + this.realloc(4); + this.buf.writeInt32LE(val, this.pos); + this.pos += 4; + }, - return function(z) { - // find the two stops which the current z is between - var low, high; + writeFixed64: function(val) { + this.realloc(8); + this.buf.writeInt32LE(val & -1, this.pos); + this.buf.writeUInt32LE(Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); + this.pos += 8; + }, - for (var i = 0; i < stops.length; i++) { - var stop = stops[i]; + writeSFixed64: function(val) { + this.realloc(8); + this.buf.writeInt32LE(val & -1, this.pos); + this.buf.writeInt32LE(Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); + this.pos += 8; + }, - if (stop[0] <= z) { - low = stop; - } + writeVarint: function(val) { + val = +val; - if (stop[0] > z) { - high = stop; - break; - } + if (val > 0xfffffff) { + writeBigVarint(val, this); + return; } - if (low && high) { - var zoomDiff = high[0] - low[0], - zoomProgress = z - low[0], - - t = base === 1 ? - zoomProgress / zoomDiff : - (Math.pow(base, zoomProgress) - 1) / (Math.pow(base, zoomDiff) - 1); + this.realloc(4); - return interpolate(low[1], high[1], t); + this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; + this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; + this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; + this.buf[this.pos++] = (val >>> 7) & 0x7f; + }, - } else if (low) { - return low[1]; + writeSVarint: function(val) { + this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2); + }, - } else if (high) { - return high[1]; - } - }; -}; + writeBoolean: function(val) { + this.writeVarint(Boolean(val)); + }, -exports['piecewise-constant'] = function(f) { - if (!f.stops) { - return constant(f); - } + writeString: function(str) { + str = String(str); + var bytes = Buffer.byteLength(str); + this.writeVarint(bytes); + this.realloc(bytes); + this.buf.write(str, this.pos); + this.pos += bytes; + }, - var stops = f.stops; + writeFloat: function(val) { + this.realloc(4); + this.buf.writeFloatLE(val, this.pos); + this.pos += 4; + }, - return function(z) { - for (var i = 0; i < stops.length; i++) { - if (stops[i][0] > z) { - return stops[i === 0 ? 0 : i - 1][1]; - } - } + writeDouble: function(val) { + this.realloc(8); + this.buf.writeDoubleLE(val, this.pos); + this.pos += 8; + }, - return stops[stops.length - 1][1]; - } -}; + writeBytes: function(buffer) { + var len = buffer.length; + this.writeVarint(len); + this.realloc(len); + for (var i = 0; i < len; i++) this.buf[this.pos++] = buffer[i]; + }, -},{}],134:[function(require,module,exports){ -'use strict'; + writeRawMessage: function(fn, obj) { + this.pos++; // reserve 1 byte for short message length -var format = require('util').format; + // write the message directly to the buffer and see how much was written + var startPos = this.pos; + fn(obj, this); + var len = this.pos - startPos; -function ValidationError(key, value /*, message, ...*/) { - this.message = ( - (key ? key + ': ' : '') + - format.apply(format, Array.prototype.slice.call(arguments, 2)) - ); + if (len >= 0x80) reallocForRawMessage(startPos, len, this); - if (value !== null && value !== undefined && value.__line__) { - this.line = value.__line__; - } -} + // finally, write the message length in the reserved place and restore the position + this.pos = startPos - 1; + this.writeVarint(len); + this.pos += len; + }, -module.exports = ValidationError; + writeMessage: function(tag, fn, obj) { + this.writeTag(tag, Pbf.Bytes); + this.writeRawMessage(fn, obj); + }, -},{"util":11}],135:[function(require,module,exports){ -'use strict'; + writePackedVarint: function(tag, arr) { this.writeMessage(tag, writePackedVarint, arr); }, + writePackedSVarint: function(tag, arr) { this.writeMessage(tag, writePackedSVarint, arr); }, + writePackedBoolean: function(tag, arr) { this.writeMessage(tag, writePackedBoolean, arr); }, + writePackedFloat: function(tag, arr) { this.writeMessage(tag, writePackedFloat, arr); }, + writePackedDouble: function(tag, arr) { this.writeMessage(tag, writePackedDouble, arr); }, + writePackedFixed32: function(tag, arr) { this.writeMessage(tag, writePackedFixed32, arr); }, + writePackedSFixed32: function(tag, arr) { this.writeMessage(tag, writePackedSFixed32, arr); }, + writePackedFixed64: function(tag, arr) { this.writeMessage(tag, writePackedFixed64, arr); }, + writePackedSFixed64: function(tag, arr) { this.writeMessage(tag, writePackedSFixed64, arr); }, -module.exports = function (output) { - for (var i = 1; i < arguments.length; i++) { - var input = arguments[i]; - for (var k in input) { - output[k] = input[k]; - } + writeBytesField: function(tag, buffer) { + this.writeTag(tag, Pbf.Bytes); + this.writeBytes(buffer); + }, + writeFixed32Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed32); + this.writeFixed32(val); + }, + writeSFixed32Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed32); + this.writeSFixed32(val); + }, + writeFixed64Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed64); + this.writeFixed64(val); + }, + writeSFixed64Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed64); + this.writeSFixed64(val); + }, + writeVarintField: function(tag, val) { + this.writeTag(tag, Pbf.Varint); + this.writeVarint(val); + }, + writeSVarintField: function(tag, val) { + this.writeTag(tag, Pbf.Varint); + this.writeSVarint(val); + }, + writeStringField: function(tag, str) { + this.writeTag(tag, Pbf.Bytes); + this.writeString(str); + }, + writeFloatField: function(tag, val) { + this.writeTag(tag, Pbf.Fixed32); + this.writeFloat(val); + }, + writeDoubleField: function(tag, val) { + this.writeTag(tag, Pbf.Fixed64); + this.writeDouble(val); + }, + writeBooleanField: function(tag, val) { + this.writeVarintField(tag, Boolean(val)); } - return output; }; -},{}],136:[function(require,module,exports){ -'use strict'; +function readVarintRemainder(val, pbf) { + var buf = pbf.buf, b; -module.exports = function getType(val) { - if (val instanceof Number) { - return 'number'; - } else if (val instanceof String) { - return 'string'; - } else if (val instanceof Boolean) { - return 'boolean'; - } else if (Array.isArray(val)) { - return 'array'; - } else if (val === null) { - return 'null'; - } else { - return typeof val; - } -}; + b = buf[pbf.pos++]; val += (b & 0x7f) * 0x10000000; if (b < 0x80) return val; + b = buf[pbf.pos++]; val += (b & 0x7f) * 0x800000000; if (b < 0x80) return val; + b = buf[pbf.pos++]; val += (b & 0x7f) * 0x40000000000; if (b < 0x80) return val; + b = buf[pbf.pos++]; val += (b & 0x7f) * 0x2000000000000; if (b < 0x80) return val; + b = buf[pbf.pos++]; val += (b & 0x7f) * 0x100000000000000; if (b < 0x80) return val; + b = buf[pbf.pos++]; val += (b & 0x7f) * 0x8000000000000000; if (b < 0x80) return val; -},{}],137:[function(require,module,exports){ -'use strict'; + throw new Error('Expected varint not more than 10 bytes'); +} -/** - * Turn jsonlint-lines-primitives objects into primitive objects - * @param value a potentially-bundled value - * @returns an unbundled value - */ -module.exports = function unbundle(value) { - if (value instanceof Number || value instanceof String || value instanceof Boolean) { - return value.valueOf(); - } else { - return value; - } -}; +function writeBigVarint(val, pbf) { + pbf.realloc(10); -},{}],138:[function(require,module,exports){ -'use strict'; + var maxPos = pbf.pos + 10; -/** - * Validate a style against the latest specification. This method is optimized - * to keep its bundle size small by refraining from requiring jslint or old - * style spec versions. - * @see validateStyleMin - * @deprecated This file exists for backwards compatibility and will be dropped in the next minor release. - */ -module.exports = require('../validate_style.min'); + while (val >= 1) { + if (pbf.pos >= maxPos) throw new Error('Given varint doesn\'t fit into 10 bytes'); + var b = val & 0xff; + pbf.buf[pbf.pos++] = b | (val >= 0x80 ? 0x80 : 0); + val /= 0x80; + } +} -},{"../validate_style.min":154}],139:[function(require,module,exports){ -'use strict'; +function reallocForRawMessage(startPos, len, pbf) { + var extraLen = + len <= 0x3fff ? 1 : + len <= 0x1fffff ? 2 : + len <= 0xfffffff ? 3 : Math.ceil(Math.log(len) / (Math.LN2 * 7)); -var ValidationError = require('../error/validation_error'); -var getType = require('../util/get_type'); -var extend = require('../util/extend'); + // if 1 byte isn't enough for encoding message length, shift the data to the right + pbf.realloc(extraLen); + for (var i = pbf.pos - 1; i >= startPos; i--) pbf.buf[i + extraLen] = pbf.buf[i]; +} -// Main recursive validation function. Tracks: -// -// - key: string representing location of validation in style tree. Used only -// for more informative error reporting. -// - value: current value from style being evaluated. May be anything from a -// high level object that needs to be descended into deeper or a simple -// scalar value. -// - valueSpec: current spec being evaluated. Tracks value. - -module.exports = function validate(options) { - - var validateFunction = require('./validate_function'); - var validateObject = require('./validate_object'); - var VALIDATORS = { - '*': function() { - return []; - }, - 'array': require('./validate_array'), - 'boolean': require('./validate_boolean'), - 'number': require('./validate_number'), - 'color': require('./validate_color'), - 'constants': require('./validate_constants'), - 'enum': require('./validate_enum'), - 'filter': require('./validate_filter'), - 'function': require('./validate_function'), - 'layer': require('./validate_layer'), - 'object': require('./validate_object'), - 'source': require('./validate_source'), - 'string': require('./validate_string') - }; +function writePackedVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]); } +function writePackedSVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]); } +function writePackedFloat(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]); } +function writePackedDouble(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]); } +function writePackedBoolean(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]); } +function writePackedFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]); } +function writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); } +function writePackedFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]); } +function writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); } - var value = options.value; - var valueSpec = options.valueSpec; - var key = options.key; - var styleSpec = options.styleSpec; - var style = options.style; +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./buffer":191}],193:[function(require,module,exports){ +module.exports={"version":"0.25.1"} +},{}],194:[function(require,module,exports){ +(function (process){ +// 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. - if (getType(value) === 'string' && value[0] === '@') { - if (styleSpec.$version > 7) { - return [new ValidationError(key, value, 'constants have been deprecated as of v8')]; - } - if (!(value in style.constants)) { - return [new ValidationError(key, value, 'constant "%s" not found', value)]; - } - options = extend({}, options, { value: style.constants[value] }); +// resolves . and .. elements in a path array with directory names there +// must be no slashes, empty elements, or device names (c:\) in the array +// (so also no leading and trailing slashes - it does not distinguish +// relative and absolute paths) +function normalizeArray(parts, allowAboveRoot) { + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = parts.length - 1; i >= 0; i--) { + var last = parts[i]; + if (last === '.') { + parts.splice(i, 1); + } else if (last === '..') { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; } + } - if (valueSpec.function && getType(value) === 'object') { - return validateFunction(options); - - } else if (valueSpec.type && VALIDATORS[valueSpec.type]) { - return VALIDATORS[valueSpec.type](options); - - } else { - return validateObject(extend({}, options, { - valueSpec: valueSpec.type ? styleSpec[valueSpec.type] : valueSpec - })); + // if the path is allowed to go above the root, restore leading ..s + if (allowAboveRoot) { + for (; up--; up) { + parts.unshift('..'); } -}; - -},{"../error/validation_error":134,"../util/extend":135,"../util/get_type":136,"./validate_array":140,"./validate_boolean":141,"./validate_color":142,"./validate_constants":143,"./validate_enum":144,"./validate_filter":145,"./validate_function":146,"./validate_layer":147,"./validate_number":149,"./validate_object":150,"./validate_source":152,"./validate_string":153}],140:[function(require,module,exports){ -'use strict'; + } -var getType = require('../util/get_type'); -var validate = require('./validate'); -var ValidationError = require('../error/validation_error'); + return parts; +} -module.exports = function validateArray(options) { - var array = options.value; - var arraySpec = options.valueSpec; - var style = options.style; - var styleSpec = options.styleSpec; - var key = options.key; - var validateArrayElement = options.arrayElementValidator || validate; +// Split a filename into [root, dir, basename, ext], unix version +// 'root' is just a slash, or nothing. +var splitPathRe = + /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; +var splitPath = function(filename) { + return splitPathRe.exec(filename).slice(1); +}; - if (getType(array) !== 'array') { - return [new ValidationError(key, array, 'array expected, %s found', getType(array))]; - } +// path.resolve([from ...], to) +// posix version +exports.resolve = function() { + var resolvedPath = '', + resolvedAbsolute = false; - if (arraySpec.length && array.length !== arraySpec.length) { - return [new ValidationError(key, array, 'array length %d expected, length %d found', arraySpec.length, array.length)]; - } + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = (i >= 0) ? arguments[i] : process.cwd(); - if (arraySpec['min-length'] && array.length < arraySpec['min-length']) { - return [new ValidationError(key, array, 'array length at least %d expected, length %d found', arraySpec['min-length'], array.length)]; + // Skip empty and invalid entries + if (typeof path !== 'string') { + throw new TypeError('Arguments to path.resolve must be strings'); + } else if (!path) { + continue; } - var arrayElementSpec = { - "type": arraySpec.value - }; + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = path.charAt(0) === '/'; + } - if (styleSpec.$version < 7) { - arrayElementSpec.function = arraySpec.function; - } + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) - if (getType(arraySpec.value) === 'object') { - arrayElementSpec = arraySpec.value; - } + // Normalize the path + resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { + return !!p; + }), !resolvedAbsolute).join('/'); - var errors = []; - for (var i = 0; i < array.length; i++) { - errors = errors.concat(validateArrayElement({ - array: array, - arrayIndex: i, - value: array[i], - valueSpec: arrayElementSpec, - style: style, - styleSpec: styleSpec, - key: key + '[' + i + ']' - })); - } - return errors; + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; }; -},{"../error/validation_error":134,"../util/get_type":136,"./validate":139}],141:[function(require,module,exports){ -'use strict'; - -var getType = require('../util/get_type'); -var ValidationError = require('../error/validation_error'); +// path.normalize(path) +// posix version +exports.normalize = function(path) { + var isAbsolute = exports.isAbsolute(path), + trailingSlash = substr(path, -1) === '/'; -module.exports = function validateBoolean(options) { - var value = options.value; - var key = options.key; - var type = getType(value); + // Normalize the path + path = normalizeArray(filter(path.split('/'), function(p) { + return !!p; + }), !isAbsolute).join('/'); - if (type !== 'boolean') { - return [new ValidationError(key, value, 'boolean expected, %s found', type)]; - } + if (!path && !isAbsolute) { + path = '.'; + } + if (path && trailingSlash) { + path += '/'; + } - return []; + return (isAbsolute ? '/' : '') + path; }; -},{"../error/validation_error":134,"../util/get_type":136}],142:[function(require,module,exports){ -'use strict'; - -var ValidationError = require('../error/validation_error'); -var getType = require('../util/get_type'); -var parseCSSColor = require('csscolorparser').parseCSSColor; - -module.exports = function validateColor(options) { - var key = options.key; - var value = options.value; - var type = getType(value); - - if (type !== 'string') { - return [new ValidationError(key, value, 'color expected, %s found', type)]; - } - - if (parseCSSColor(value) === null) { - return [new ValidationError(key, value, 'color expected, "%s" found', value)]; - } - - return []; +// posix version +exports.isAbsolute = function(path) { + return path.charAt(0) === '/'; }; -},{"../error/validation_error":134,"../util/get_type":136,"csscolorparser":114}],143:[function(require,module,exports){ -'use strict'; - -var ValidationError = require('../error/validation_error'); -var getType = require('../util/get_type'); - -module.exports = function validateConstants(options) { - var key = options.key; - var constants = options.value; - var styleSpec = options.styleSpec; - - if (styleSpec.$version > 7) { - if (constants) { - return [new ValidationError(key, constants, 'constants have been deprecated as of v8')]; - } else { - return []; - } - } else { - var type = getType(constants); - if (type !== 'object') { - return [new ValidationError(key, constants, 'object expected, %s found', type)]; - } - - var errors = []; - for (var constantName in constants) { - if (constantName[0] !== '@') { - errors.push(new ValidationError(key + '.' + constantName, constants[constantName], 'constants must start with "@"')); - } - } - return errors; +// posix version +exports.join = function() { + var paths = Array.prototype.slice.call(arguments, 0); + return exports.normalize(filter(paths, function(p, index) { + if (typeof p !== 'string') { + throw new TypeError('Arguments to path.join must be strings'); } - + return p; + }).join('/')); }; -},{"../error/validation_error":134,"../util/get_type":136}],144:[function(require,module,exports){ -'use strict'; - -var ValidationError = require('../error/validation_error'); -var unbundle = require('../util/unbundle_jsonlint'); -module.exports = function validateEnum(options) { - var key = options.key; - var value = options.value; - var valueSpec = options.valueSpec; - var errors = []; +// path.relative(from, to) +// posix version +exports.relative = function(from, to) { + from = exports.resolve(from).substr(1); + to = exports.resolve(to).substr(1); - if (valueSpec.values.indexOf(unbundle(value)) === -1) { - errors.push(new ValidationError(key, value, 'expected one of [%s], %s found', valueSpec.values.join(', '), value)); + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== '') break; } - return errors; -}; - -},{"../error/validation_error":134,"../util/unbundle_jsonlint":137}],145:[function(require,module,exports){ -'use strict'; - -var ValidationError = require('../error/validation_error'); -var validateEnum = require('./validate_enum'); -var getType = require('../util/get_type'); -var unbundle = require('../util/unbundle_jsonlint'); -module.exports = function validateFilter(options) { - var value = options.value; - var key = options.key; - var styleSpec = options.styleSpec; - var type; + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== '') break; + } - var errors = []; + if (start > end) return []; + return arr.slice(start, end - start + 1); + } - if (getType(value) !== 'array') { - return [new ValidationError(key, value, 'array expected, %s found', getType(value))]; - } + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); - if (value.length < 1) { - return [new ValidationError(key, value, 'filter array must have at least 1 element')]; + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; } + } - errors = errors.concat(validateEnum({ - key: key + '[0]', - value: value[0], - valueSpec: styleSpec.filter_operator, - style: options.style, - styleSpec: options.styleSpec - })); - - switch (unbundle(value[0])) { - case '<': - case '<=': - case '>': - case '>=': - if (value.length >= 2 && value[1] == '$type') { - errors.push(new ValidationError(key, value, '"$type" cannot be use with operator "%s"', value[0])); - } - /* falls through */ - case '==': - case '!=': - if (value.length != 3) { - errors.push(new ValidationError(key, value, 'filter array for operator "%s" must have 3 elements', value[0])); - } - /* falls through */ - case 'in': - case '!in': - if (value.length >= 2) { - type = getType(value[1]); - if (type !== 'string') { - errors.push(new ValidationError(key + '[1]', value[1], 'string expected, %s found', type)); - } else if (value[1][0] === '@') { - errors.push(new ValidationError(key + '[1]', value[1], 'filter key cannot be a constant')); - } - } - for (var i = 2; i < value.length; i++) { - type = getType(value[i]); - if (value[1] == '$type') { - errors = errors.concat(validateEnum({ - key: key + '[' + i + ']', - value: value[i], - valueSpec: styleSpec.geometry_type, - style: options.style, - styleSpec: options.styleSpec - })); - } else if (type === 'string' && value[i][0] === '@') { - errors.push(new ValidationError(key + '[' + i + ']', value[i], 'filter value cannot be a constant')); - } else if (type !== 'string' && type !== 'number' && type !== 'boolean') { - errors.push(new ValidationError(key + '[' + i + ']', value[i], 'string, number, or boolean expected, %s found', type)); - } - } - break; + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push('..'); + } - case 'any': - case 'all': - case 'none': - for (i = 1; i < value.length; i++) { - errors = errors.concat(validateFilter({ - key: key + '[' + i + ']', - value: value[i], - style: options.style, - styleSpec: options.styleSpec - })); - } - break; - } + outputParts = outputParts.concat(toParts.slice(samePartsLength)); - return errors; + return outputParts.join('/'); }; -},{"../error/validation_error":134,"../util/get_type":136,"../util/unbundle_jsonlint":137,"./validate_enum":144}],146:[function(require,module,exports){ -'use strict'; - -var ValidationError = require('../error/validation_error'); -var getType = require('../util/get_type'); -var validate = require('./validate'); -var validateObject = require('./validate_object'); -var validateArray = require('./validate_array'); - -module.exports = function validateFunction(options) { - var originalValueSpec = options.valueSpec; - - return validateObject({ - key: options.key, - value: options.value, - valueSpec: options.styleSpec.function, - style: options.style, - styleSpec: options.styleSpec, - objectElementValidators: { stops: validateFunctionStops } - }); +exports.sep = '/'; +exports.delimiter = ':'; - function validateFunctionStops(options) { - var errors = []; - var value = options.value; +exports.dirname = function(path) { + var result = splitPath(path), + root = result[0], + dir = result[1]; - errors = errors.concat(validateArray({ - key: options.key, - value: value, - valueSpec: options.valueSpec, - style: options.style, - styleSpec: options.styleSpec, - arrayElementValidator: validateFunctionStop - })); + if (!root && !dir) { + // No dirname whatsoever + return '.'; + } - if (getType(value) === 'array' && value.length === 0) { - errors.push(new ValidationError(options.key, value, 'array must have at least one stop')); - } + if (dir) { + // It has a dirname, strip trailing slash + dir = dir.substr(0, dir.length - 1); + } - return errors; - } + return root + dir; +}; - function validateFunctionStop(options) { - var errors = []; - var value = options.value; - var key = options.key; - if (getType(value) !== 'array') { - return [new ValidationError(key, value, 'array expected, %s found', getType(value))]; - } +exports.basename = function(path, ext) { + var f = splitPath(path)[2]; + // TODO: make this comparison case-insensitive on windows? + if (ext && f.substr(-1 * ext.length) === ext) { + f = f.substr(0, f.length - ext.length); + } + return f; +}; - if (value.length !== 2) { - return [new ValidationError(key, value, 'array length %d expected, length %d found', 2, value.length)]; - } - errors = errors.concat(validate({ - key: key + '[0]', - value: value[0], - valueSpec: {type: 'number'}, - style: options.style, - styleSpec: options.styleSpec - })); +exports.extname = function(path) { + return splitPath(path)[3]; +}; - errors = errors.concat(validate({ - key: key + '[1]', - value: value[1], - valueSpec: originalValueSpec, - style: options.style, - styleSpec: options.styleSpec - })); +function filter (xs, f) { + if (xs.filter) return xs.filter(f); + var res = []; + for (var i = 0; i < xs.length; i++) { + if (f(xs[i], i, xs)) res.push(xs[i]); + } + return res; +} - if (getType(value[0]) === 'number') { - if (originalValueSpec.function === 'piecewise-constant' && value[0] % 1 !== 0) { - errors.push(new ValidationError(key + '[0]', value[0], 'zoom level for piecewise-constant functions must be an integer')); - } +// String.prototype.substr - negative index don't work in IE8 +var substr = 'ab'.substr(-1) === 'b' + ? function (str, start, len) { return str.substr(start, len) } + : function (str, start, len) { + if (start < 0) start = str.length + start; + return str.substr(start, len); + } +; - if (options.arrayIndex !== 0) { - if (value[0] < options.array[options.arrayIndex - 1][0]) { - errors.push(new ValidationError(key + '[0]', value[0], 'array stops must appear in ascending order')); - } - } - } +}).call(this,require('_process')) +},{"_process":197}],195:[function(require,module,exports){ +'use strict'; - return errors; - } +module.exports = Pbf; -}; +var ieee754 = require('ieee754'); -},{"../error/validation_error":134,"../util/get_type":136,"./validate":139,"./validate_array":140,"./validate_object":150}],147:[function(require,module,exports){ -'use strict'; +function Pbf(buf) { + this.buf = ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0); + this.pos = 0; + this.type = 0; + this.length = this.buf.length; +} -var ValidationError = require('../error/validation_error'); -var unbundle = require('../util/unbundle_jsonlint'); -var validateObject = require('./validate_object'); -var validateFilter = require('./validate_filter'); -var validatePaintProperty = require('./validate_paint_property'); -var validateLayoutProperty = require('./validate_layout_property'); -var extend = require('../util/extend'); +Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum +Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64 +Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields +Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32 -module.exports = function validateLayer(options) { - var errors = []; +var SHIFT_LEFT_32 = (1 << 16) * (1 << 16), + SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32; - var layer = options.value; - var key = options.key; - var style = options.style; - var styleSpec = options.styleSpec; +Pbf.prototype = { - if (!layer.type && !layer.ref) { - errors.push(new ValidationError(key, layer, 'either "type" or "ref" is required')); - } - var type = unbundle(layer.type); - var ref = unbundle(layer.ref); + destroy: function() { + this.buf = null; + }, - if (layer.id) { - for (var i = 0; i < options.arrayIndex; i++) { - var otherLayer = style.layers[i]; - if (unbundle(otherLayer.id) === unbundle(layer.id)) { - errors.push(new ValidationError(key, layer.id, 'duplicate layer id "%s", previously used at line %d', layer.id, otherLayer.id.__line__)); - } - } - } + // === READING ================================================================= - if ('ref' in layer) { - ['type', 'source', 'source-layer', 'filter', 'layout'].forEach(function (p) { - if (p in layer) { - errors.push(new ValidationError(key, layer[p], '"%s" is prohibited for ref layers', p)); - } - }); + readFields: function(readField, result, end) { + end = end || this.length; - var parent; + while (this.pos < end) { + var val = this.readVarint(), + tag = val >> 3, + startPos = this.pos; - style.layers.forEach(function(layer) { - if (layer.id == ref) parent = layer; - }); + this.type = val & 0x7; + readField(tag, result, this); - if (!parent) { - errors.push(new ValidationError(key, layer.ref, 'ref layer "%s" not found', ref)); - } else if (parent.ref) { - errors.push(new ValidationError(key, layer.ref, 'ref cannot reference another ref layer')); - } else { - type = unbundle(parent.type); - } - } else if (type !== 'background') { - if (!layer.source) { - errors.push(new ValidationError(key, layer, 'missing required property "source"')); - } else { - var source = style.sources[layer.source]; - if (!source) { - errors.push(new ValidationError(key, layer.source, 'source "%s" not found', layer.source)); - } else if (source.type == 'vector' && type == 'raster') { - errors.push(new ValidationError(key, layer.source, 'layer "%s" requires a raster source', layer.id)); - } else if (source.type == 'raster' && type != 'raster') { - errors.push(new ValidationError(key, layer.source, 'layer "%s" requires a vector source', layer.id)); - } else if (source.type == 'vector' && !layer['source-layer']) { - errors.push(new ValidationError(key, layer, 'layer "%s" must specify a "source-layer"', layer.id)); - } + if (this.pos === startPos) this.skip(val); } - } + return result; + }, - errors = errors.concat(validateObject({ - key: key, - value: layer, - valueSpec: styleSpec.layer, - style: options.style, - styleSpec: options.styleSpec, - objectElementValidators: { - filter: validateFilter, - layout: function(options) { - return validateObject({ - layer: layer, - key: options.key, - value: options.value, - style: options.style, - styleSpec: options.styleSpec, - objectElementValidators: { - '*': function(options) { - return validateLayoutProperty(extend({layerType: type}, options)); - } - } - }); - }, - paint: function(options) { - return validateObject({ - layer: layer, - key: options.key, - value: options.value, - style: options.style, - styleSpec: options.styleSpec, - objectElementValidators: { - '*': function(options) { - return validatePaintProperty(extend({layerType: type}, options)); - } - } - }); - } - } - })); + readMessage: function(readField, result) { + return this.readFields(readField, result, this.readVarint() + this.pos); + }, - return errors; -}; + readFixed32: function() { + var val = readUInt32(this.buf, this.pos); + this.pos += 4; + return val; + }, -},{"../error/validation_error":134,"../util/extend":135,"../util/unbundle_jsonlint":137,"./validate_filter":145,"./validate_layout_property":148,"./validate_object":150,"./validate_paint_property":151}],148:[function(require,module,exports){ -'use strict'; + readSFixed32: function() { + var val = readInt32(this.buf, this.pos); + this.pos += 4; + return val; + }, -var validate = require('./validate'); -var ValidationError = require('../error/validation_error'); - -/** - * @param options - * @param {string} [options.key] - * @param options.value - * @param [options.valueSpec] - * @param [options.style] - * @param [options.styleSpec] - * @param [options.layer] - * @param options.objectKey - */ -module.exports = function validateLayoutProperty(options) { - var key = options.key; - var style = options.style; - var styleSpec = options.styleSpec; - var value = options.value; - var propertyKey = options.objectKey; - var layerSpec = styleSpec['layout_' + options.layerType]; - - if (options.valueSpec || layerSpec[propertyKey]) { - return validate({ - key: options.key, - value: value, - valueSpec: options.valueSpec || layerSpec[propertyKey], - style: style, - styleSpec: styleSpec - }); + // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed) - } else { - return [new ValidationError(key, value, 'unknown property "%s"', propertyKey)]; - } + readFixed64: function() { + var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32; + this.pos += 8; + return val; + }, -}; + readSFixed64: function() { + var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32; + this.pos += 8; + return val; + }, -},{"../error/validation_error":134,"./validate":139}],149:[function(require,module,exports){ -'use strict'; + readFloat: function() { + var val = ieee754.read(this.buf, this.pos, true, 23, 4); + this.pos += 4; + return val; + }, -var getType = require('../util/get_type'); -var ValidationError = require('../error/validation_error'); + readDouble: function() { + var val = ieee754.read(this.buf, this.pos, true, 52, 8); + this.pos += 8; + return val; + }, -module.exports = function validateNumber(options) { - var key = options.key; - var value = options.value; - var valueSpec = options.valueSpec; - var type = getType(value); + readVarint: function(isSigned) { + var buf = this.buf, + val, b; - if (type !== 'number') { - return [new ValidationError(key, value, 'number expected, %s found', type)]; - } + b = buf[this.pos++]; val = b & 0x7f; if (b < 0x80) return val; + b = buf[this.pos++]; val |= (b & 0x7f) << 7; if (b < 0x80) return val; + b = buf[this.pos++]; val |= (b & 0x7f) << 14; if (b < 0x80) return val; + b = buf[this.pos++]; val |= (b & 0x7f) << 21; if (b < 0x80) return val; + b = buf[this.pos]; val |= (b & 0x0f) << 28; - if ('minimum' in valueSpec && value < valueSpec.minimum) { - return [new ValidationError(key, value, '%s is less than the minimum value %s', value, valueSpec.minimum)]; - } + return readVarintRemainder(val, isSigned, this); + }, - if ('maximum' in valueSpec && value > valueSpec.maximum) { - return [new ValidationError(key, value, '%s is greater than the maximum value %s', value, valueSpec.maximum)]; - } + readVarint64: function() { // for compatibility with v2.0.1 + return this.readVarint(true); + }, - return []; -}; + readSVarint: function() { + var num = this.readVarint(); + return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding + }, -},{"../error/validation_error":134,"../util/get_type":136}],150:[function(require,module,exports){ -'use strict'; + readBoolean: function() { + return Boolean(this.readVarint()); + }, -var ValidationError = require('../error/validation_error'); -var getType = require('../util/get_type'); -var validate = require('./validate'); - -module.exports = function validateObject(options) { - var key = options.key; - var object = options.value; - var valueSpec = options.valueSpec; - var objectElementValidators = options.objectElementValidators || {}; - var style = options.style; - var styleSpec = options.styleSpec; - var errors = []; + readString: function() { + var end = this.readVarint() + this.pos, + str = readUtf8(this.buf, this.pos, end); + this.pos = end; + return str; + }, - var type = getType(object); - if (type !== 'object') { - return [new ValidationError(key, object, 'object expected, %s found', type)]; - } + readBytes: function() { + var end = this.readVarint() + this.pos, + buffer = this.buf.subarray(this.pos, end); + this.pos = end; + return buffer; + }, - for (var objectKey in object) { - var valueSpecKey = objectKey.split('.')[0]; // treat 'paint.*' as 'paint' - var objectElementSpec = valueSpec && (valueSpec[valueSpecKey] || valueSpec['*']); - var objectElementValidator = objectElementValidators[valueSpecKey] || objectElementValidators['*']; + // verbose for performance reasons; doesn't affect gzipped size - if (objectElementSpec || objectElementValidator) { - errors = errors.concat((objectElementValidator || validate)({ - key: (key ? key + '.' : key) + objectKey, - value: object[objectKey], - valueSpec: objectElementSpec, - style: style, - styleSpec: styleSpec, - object: object, - objectKey: objectKey - })); + readPackedVarint: function(arr, isSigned) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readVarint(isSigned)); + return arr; + }, + readPackedSVarint: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readSVarint()); + return arr; + }, + readPackedBoolean: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readBoolean()); + return arr; + }, + readPackedFloat: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readFloat()); + return arr; + }, + readPackedDouble: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readDouble()); + return arr; + }, + readPackedFixed32: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readFixed32()); + return arr; + }, + readPackedSFixed32: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readSFixed32()); + return arr; + }, + readPackedFixed64: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readFixed64()); + return arr; + }, + readPackedSFixed64: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readSFixed64()); + return arr; + }, - // tolerate root-level extra keys & arbitrary layer properties - // TODO remove this layer-specific logic - } else if (key !== '' && key.split('.').length !== 1) { - errors.push(new ValidationError(key, object[objectKey], 'unknown property "%s"', objectKey)); - } - } + skip: function(val) { + var type = val & 0x7; + if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {} + else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos; + else if (type === Pbf.Fixed32) this.pos += 4; + else if (type === Pbf.Fixed64) this.pos += 8; + else throw new Error('Unimplemented type: ' + type); + }, - for (valueSpecKey in valueSpec) { - if (valueSpec[valueSpecKey].required && valueSpec[valueSpecKey]['default'] === undefined && object[valueSpecKey] === undefined) { - errors.push(new ValidationError(key, object, 'missing required property "%s"', valueSpecKey)); - } - } + // === WRITING ================================================================= - return errors; -}; + writeTag: function(tag, type) { + this.writeVarint((tag << 3) | type); + }, -},{"../error/validation_error":134,"../util/get_type":136,"./validate":139}],151:[function(require,module,exports){ -'use strict'; + realloc: function(min) { + var length = this.length || 16; -var validate = require('./validate'); -var ValidationError = require('../error/validation_error'); + while (length < this.pos + min) length *= 2; -/** - * @param options - * @param {string} [options.key] - * @param options.value - * @param [options.valueSpec] - * @param [options.style] - * @param [options.styleSpec] - * @param [options.layer] - * @param options.objectKey - */ -module.exports = function validatePaintProperty(options) { - var key = options.key; - var style = options.style; - var styleSpec = options.styleSpec; - var value = options.value; - var propertyKey = options.objectKey; - var layerSpec = styleSpec['paint_' + options.layerType]; + if (length !== this.length) { + var buf = new Uint8Array(length); + buf.set(this.buf); + this.buf = buf; + this.length = length; + } + }, - var transitionMatch = propertyKey.match(/^(.*)-transition$/); + finish: function() { + this.length = this.pos; + this.pos = 0; + return this.buf.subarray(0, this.length); + }, - if (transitionMatch && layerSpec[transitionMatch[1]] && layerSpec[transitionMatch[1]].transition) { - return validate({ - key: key, - value: value, - valueSpec: styleSpec.transition, - style: style, - styleSpec: styleSpec - }); + writeFixed32: function(val) { + this.realloc(4); + writeInt32(this.buf, val, this.pos); + this.pos += 4; + }, - } else if (options.valueSpec || layerSpec[propertyKey]) { - return validate({ - key: options.key, - value: value, - valueSpec: options.valueSpec || layerSpec[propertyKey], - style: style, - styleSpec: styleSpec - }); + writeSFixed32: function(val) { + this.realloc(4); + writeInt32(this.buf, val, this.pos); + this.pos += 4; + }, - } else { - return [new ValidationError(key, value, 'unknown property "%s"', propertyKey)]; - } + writeFixed64: function(val) { + this.realloc(8); + writeInt32(this.buf, val & -1, this.pos); + writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); + this.pos += 8; + }, -}; + writeSFixed64: function(val) { + this.realloc(8); + writeInt32(this.buf, val & -1, this.pos); + writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); + this.pos += 8; + }, -},{"../error/validation_error":134,"./validate":139}],152:[function(require,module,exports){ -'use strict'; + writeVarint: function(val) { + val = +val || 0; -var ValidationError = require('../error/validation_error'); -var unbundle = require('../util/unbundle_jsonlint'); -var validateObject = require('./validate_object'); -var validateEnum = require('./validate_enum'); - -module.exports = function validateSource(options) { - var value = options.value; - var key = options.key; - var styleSpec = options.styleSpec; - var style = options.style; - - if (!value.type) { - return [new ValidationError(key, value, '"type" is required')]; - } - - var type = unbundle(value.type); - switch (type) { - case 'vector': - case 'raster': - var errors = []; - errors = errors.concat(validateObject({ - key: key, - value: value, - valueSpec: styleSpec.source_tile, - style: options.style, - styleSpec: styleSpec - })); - if ('url' in value) { - for (var prop in value) { - if (['type', 'url', 'tileSize'].indexOf(prop) < 0) { - errors.push(new ValidationError(key + '.' + prop, value[prop], 'a source with a "url" property may not include a "%s" property', prop)); - } - } - } - return errors; - - case 'geojson': - return validateObject({ - key: key, - value: value, - valueSpec: styleSpec.source_geojson, - style: style, - styleSpec: styleSpec - }); + if (val > 0xfffffff || val < 0) { + writeBigVarint(val, this); + return; + } - case 'video': - return validateObject({ - key: key, - value: value, - valueSpec: styleSpec.source_video, - style: style, - styleSpec: styleSpec - }); + this.realloc(4); - case 'image': - return validateObject({ - key: key, - value: value, - valueSpec: styleSpec.source_image, - style: style, - styleSpec: styleSpec - }); + this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; + this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; + this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; + this.buf[this.pos++] = (val >>> 7) & 0x7f; + }, - default: - return validateEnum({ - key: key + '.type', - value: value.type, - valueSpec: {values: ['vector', 'raster', 'geojson', 'video', 'image']}, - style: style, - styleSpec: styleSpec - }); - } -}; + writeSVarint: function(val) { + this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2); + }, -},{"../error/validation_error":134,"../util/unbundle_jsonlint":137,"./validate_enum":144,"./validate_object":150}],153:[function(require,module,exports){ -'use strict'; + writeBoolean: function(val) { + this.writeVarint(Boolean(val)); + }, -var getType = require('../util/get_type'); -var ValidationError = require('../error/validation_error'); + writeString: function(str) { + str = String(str); + this.realloc(str.length * 4); -module.exports = function validateString(options) { - var value = options.value; - var key = options.key; - var type = getType(value); + this.pos++; // reserve 1 byte for short string length - if (type !== 'string') { - return [new ValidationError(key, value, 'string expected, %s found', type)]; - } + var startPos = this.pos; + // write the string directly to the buffer and see how much was written + this.pos = writeUtf8(this.buf, str, this.pos); + var len = this.pos - startPos; - return []; -}; + if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); -},{"../error/validation_error":134,"../util/get_type":136}],154:[function(require,module,exports){ -'use strict'; + // finally, write the message length in the reserved place and restore the position + this.pos = startPos - 1; + this.writeVarint(len); + this.pos += len; + }, -var validateConstants = require('./validate/validate_constants'); -var validate = require('./validate/validate'); -var latestStyleSpec = require('../reference/latest.min'); + writeFloat: function(val) { + this.realloc(4); + ieee754.write(this.buf, val, this.pos, true, 23, 4); + this.pos += 4; + }, -/** - * Validate a Mapbox GL style against the style specification. This entrypoint, - * `mapbox-gl-style-spec/lib/validate_style.min`, is designed to produce as - * small a browserify bundle as possible by omitting unnecessary functionality - * and legacy style specifications. - * - * @param {Object} style The style to be validated. - * @param {Object} [styleSpec] The style specification to validate against. - * If omitted, the latest style spec is used. - * @returns {Array} - * @example - * var validate = require('mapbox-gl-style-spec/lib/validate_style.min'); - * var errors = validate(style); - */ -function validateStyleMin(style, styleSpec) { - styleSpec = styleSpec || latestStyleSpec; + writeDouble: function(val) { + this.realloc(8); + ieee754.write(this.buf, val, this.pos, true, 52, 8); + this.pos += 8; + }, - var errors = []; + writeBytes: function(buffer) { + var len = buffer.length; + this.writeVarint(len); + this.realloc(len); + for (var i = 0; i < len; i++) this.buf[this.pos++] = buffer[i]; + }, - errors = errors.concat(validate({ - key: '', - value: style, - valueSpec: styleSpec.$root, - styleSpec: styleSpec, - style: style - })); + writeRawMessage: function(fn, obj) { + this.pos++; // reserve 1 byte for short message length - if (styleSpec.$version > 7 && style.constants) { - errors = errors.concat(validateConstants({ - key: 'constants', - value: style.constants, - style: style, - styleSpec: styleSpec - })); - } + // write the message directly to the buffer and see how much was written + var startPos = this.pos; + fn(obj, this); + var len = this.pos - startPos; - return sortErrors(errors); -} + if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); -validateStyleMin.source = wrapCleanErrors(require('./validate/validate_source')); -validateStyleMin.layer = wrapCleanErrors(require('./validate/validate_layer')); -validateStyleMin.filter = wrapCleanErrors(require('./validate/validate_filter')); -validateStyleMin.paintProperty = wrapCleanErrors(require('./validate/validate_paint_property')); -validateStyleMin.layoutProperty = wrapCleanErrors(require('./validate/validate_layout_property')); + // finally, write the message length in the reserved place and restore the position + this.pos = startPos - 1; + this.writeVarint(len); + this.pos += len; + }, -function sortErrors(errors) { - return [].concat(errors).sort(function (a, b) { - return a.line - b.line; - }); -} + writeMessage: function(tag, fn, obj) { + this.writeTag(tag, Pbf.Bytes); + this.writeRawMessage(fn, obj); + }, -function wrapCleanErrors(inner) { - return function() { - return sortErrors(inner.apply(this, arguments)); - }; -} + writePackedVarint: function(tag, arr) { this.writeMessage(tag, writePackedVarint, arr); }, + writePackedSVarint: function(tag, arr) { this.writeMessage(tag, writePackedSVarint, arr); }, + writePackedBoolean: function(tag, arr) { this.writeMessage(tag, writePackedBoolean, arr); }, + writePackedFloat: function(tag, arr) { this.writeMessage(tag, writePackedFloat, arr); }, + writePackedDouble: function(tag, arr) { this.writeMessage(tag, writePackedDouble, arr); }, + writePackedFixed32: function(tag, arr) { this.writeMessage(tag, writePackedFixed32, arr); }, + writePackedSFixed32: function(tag, arr) { this.writeMessage(tag, writePackedSFixed32, arr); }, + writePackedFixed64: function(tag, arr) { this.writeMessage(tag, writePackedFixed64, arr); }, + writePackedSFixed64: function(tag, arr) { this.writeMessage(tag, writePackedSFixed64, arr); }, -module.exports = validateStyleMin; - -},{"../reference/latest.min":156,"./validate/validate":139,"./validate/validate_constants":143,"./validate/validate_filter":145,"./validate/validate_layer":147,"./validate/validate_layout_property":148,"./validate/validate_paint_property":151,"./validate/validate_source":152}],155:[function(require,module,exports){ -module.exports = require('./v8.json'); - -},{"./v8.json":157}],156:[function(require,module,exports){ -module.exports = require('./v8.min.json'); - -},{"./v8.min.json":158}],157:[function(require,module,exports){ -module.exports={ - "$version": 8, - "$root": { - "version": { - "required": true, - "type": "enum", - "values": [8], - "doc": "Stylesheet version number. Must be 8.", - "example": 8 - }, - "name": { - "type": "string", - "doc": "A human-readable name for the style.", - "example": "Bright" - }, - "metadata": { - "type": "*", - "doc": "Arbitrary properties useful to track with the stylesheet, but do not influence rendering. Properties should be prefixed to avoid collisions, like 'mapbox:'." - }, - "center": { - "type": "array", - "value": "number", - "doc": "Default map center in longitude and latitude. The style center will be used only if the map has not been positioned by other means (e.g. map options or user interaction).", - "example": [-73.9749, 40.7736] - }, - "zoom": { - "type": "number", - "doc": "Default zoom level. The style zoom will be used only if the map has not been positioned by other means (e.g. map options or user interaction).", - "example": 12.5 - }, - "bearing": { - "type": "number", - "default": 0, - "period": 360, - "units": "degrees", - "doc": "Default bearing, in degrees. The style bearing will be used only if the map has not been positioned by other means (e.g. map options or user interaction).", - "example": 29 - }, - "pitch": { - "type": "number", - "default": 0, - "units": "degrees", - "doc": "Default pitch, in degrees. Zero is perpendicular to the surface. The style pitch will be used only if the map has not been positioned by other means (e.g. map options or user interaction).", - "example": 50 - }, - "sources": { - "required": true, - "type": "sources", - "doc": "Data source specifications.", - "example": { - "mapbox-streets": { - "type": "vector", - "url": "mapbox://mapbox.mapbox-streets-v6" - } - } - }, - "sprite": { - "type": "string", - "doc": "A base URL for retrieving the sprite image and metadata. The extensions `.png`, `.json` and scale factor `@2x.png` will be automatically appended.", - "example": "mapbox://sprites/mapbox/bright-v8" - }, - "glyphs": { - "type": "string", - "doc": "A URL template for loading signed-distance-field glyph sets in PBF format. Valid tokens are {fontstack} and {range}.", - "example": "mapbox://fonts/mapbox/{fontstack}/{range}.pbf" - }, - "transition": { - "type": "transition", - "doc": "A global transition definition to use as a default across properties.", - "example": { - "duration": 300, - "delay": 0 - } + writeBytesField: function(tag, buffer) { + this.writeTag(tag, Pbf.Bytes); + this.writeBytes(buffer); }, - "layers": { - "required": true, - "type": "array", - "value": "layer", - "doc": "Layers will be drawn in the order of this array.", - "example": [ - { - "id": "water", - "source": "mapbox-streets", - "source-layer": "water", - "type": "fill", - "paint": { - "fill-color": "#00ffff" - } - } - ] - } - }, - "sources": { - "*": { - "type": "source", - "doc": "Specification of a data source. For vector and raster sources, either TileJSON or a URL to a TileJSON must be provided. For GeoJSON and video sources, a URL must be provided." - } - }, - "source": [ - "source_tile", - "source_geojson", - "source_video", - "source_image" - ], - "source_tile": { - "type": { - "required": true, - "type": "enum", - "values": [ - "vector", - "raster" - ], - "doc": "The data type of the tile source." - }, - "url": { - "type": "string", - "doc": "A URL to a TileJSON resource. Supported protocols are `http:`, `https:`, and `mapbox://`." - }, - "tiles": { - "type": "array", - "value": "string", - "doc": "An array of one or more tile source URLs, as in the TileJSON spec." - }, - "minzoom": { - "type": "number", - "default": 0, - "doc": "Minimum zoom level for which tiles are available, as in the TileJSON spec." - }, - "maxzoom": { - "type": "number", - "default": 22, - "doc": "Maximum zoom level for which tiles are available, as in the TileJSON spec. Data from tiles at the maxzoom are used when displaying the map at higher zoom levels." - }, - "tileSize": { - "type": "number", - "default": 512, - "units": "pixels", - "doc": "The minimum visual size to display tiles for this layer. Only configurable for raster layers." - }, - "*": { - "type": "*", - "doc": "Other keys to configure the data source." - } - }, - "source_geojson": { - "type": { - "required": true, - "type": "enum", - "values": [ - "geojson" - ], - "doc": "The data type of the GeoJSON source." - }, - "data": { - "type": "*", - "doc": "A URL to a GeoJSON file, or inline GeoJSON." - }, - "maxzoom": { - "type": "number", - "default": 14, - "doc": "Maximum zoom level at which to create vector tiles (higher means greater detail at high zoom levels)." - }, - "buffer": { - "type": "number", - "default": 64, - "doc": "Tile buffer size on each side (higher means fewer rendering artifacts near tile edges but slower performance)." - }, - "tolerance": { - "type": "number", - "default": 3, - "doc": "Douglas-Peucker simplification tolerance (higher means simpler geometries and faster performance)." - }, - "cluster": { - "type": "boolean", - "default": false, - "doc": "If the data is a collection of point features, setting this to true clusters the points by radius into groups." - }, - "clusterRadius": { - "type": "number", - "default": 400, - "doc": "Radius of each cluster when clustering points, relative to 4096 tile." - }, - "clusterMaxZoom": { - "type": "number", - "doc": "Max zoom to cluster points on. Defaults to one zoom less than maxzoom (so that last zoom features are not clustered)." - } - }, - "source_video": { - "type": { - "required": true, - "type": "enum", - "values": [ - "video" - ], - "doc": "The data type of the video source." - }, - "urls": { - "required": true, - "type": "array", - "value": "string", - "doc": "URLs to video content in order of preferred format." - }, - "coordinates": { - "required": true, - "doc": "Corners of video specified in longitude, latitude pairs.", - "type": "array", - "length": 4, - "value": { - "type": "array", - "length": 2, - "value": "number", - "doc": "A single longitude, latitude pair." - } - } - }, - "source_image": { - "type": { - "required": true, - "type": "enum", - "values": [ - "image" - ], - "doc": "The data type of the image source." - }, - "url": { - "required": true, - "type": "string", - "doc": "URL that points to an image" - }, - "coordinates": { - "required": true, - "doc": "Corners of image specified in longitude, latitude pairs.", - "type": "array", - "length": 4, - "value": { - "type": "array", - "length": 2, - "value": "number", - "doc": "A single longitude, latitude pair." - } - } - }, - "layer": { - "id": { - "type": "string", - "doc": "Unique layer name.", - "required": true - }, - "type": { - "type": "enum", - "values": [ - "fill", - "line", - "symbol", - "circle", - "raster", - "background" - ], - "doc": "Rendering type of this layer." - }, - "metadata": { - "type": "*", - "doc": "Arbitrary properties useful to track with the layer, but do not influence rendering. Properties should be prefixed to avoid collisions, like 'mapbox:'." - }, - "ref": { - "type": "string", - "doc": "References another layer to copy `type`, `source`, `source-layer`, `minzoom`, `maxzoom`, `filter`, and `layout` properties from. This allows the layers to share processing and be more efficient." - }, - "source": { - "type": "string", - "doc": "Name of a source description to be used for this layer." - }, - "source-layer": { - "type": "string", - "doc": "Layer to use from a vector tile source. Required if the source supports multiple layers." - }, - "minzoom": { - "type": "number", - "minimum": 0, - "maximum": 22, - "doc": "The minimum zoom level on which the layer gets parsed and appears on." - }, - "maxzoom": { - "type": "number", - "minimum": 0, - "maximum": 22, - "doc": "The maximum zoom level on which the layer gets parsed and appears on." - }, - "interactive": { - "type": "boolean", - "doc": "Enable querying of feature data from this layer for interactivity.", - "default": false - }, - "filter": { - "type": "filter", - "doc": "A expression specifying conditions on source features. Only features that match the filter are displayed." - }, - "layout": { - "type": "layout", - "doc": "Layout properties for the layer." - }, - "paint": { - "type": "paint", - "doc": "Default paint properties for this layer." - }, - "paint.*": { - "type": "paint", - "doc": "Class-specific paint properties for this layer. The class name is the part after the first dot." - } - }, - "layout": [ - "layout_fill", - "layout_line", - "layout_circle", - "layout_symbol", - "layout_raster", - "layout_background" - ], - "layout_background": { - "visibility": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "visible", - "none" - ], - "default": "visible", - "doc": "The display of this layer. `none` hides this layer." - } - }, - "layout_fill": { - "visibility": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "visible", - "none" - ], - "default": "visible", - "doc": "The display of this layer. `none` hides this layer." - } - }, - "layout_circle": { - "visibility": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "visible", - "none" - ], - "default": "visible", - "doc": "The display of this layer. `none` hides this layer." - } - }, - "layout_line": { - "line-cap": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "butt", - "round", - "square" - ], - "default": "butt", - "doc": "The display of line endings." - }, - "line-join": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "bevel", - "round", - "miter" - ], - "default": "miter", - "doc": "The display of lines when joining." - }, - "line-miter-limit": { - "type": "number", - "default": 2, - "function": "interpolated", - "doc": "Used to automatically convert miter joins to bevel joins for sharp angles.", - "requires": [ - { - "line-join": "miter" - } - ] + writeFixed32Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed32); + this.writeFixed32(val); }, - "line-round-limit": { - "type": "number", - "default": 1.05, - "function": "interpolated", - "doc": "Used to automatically convert round joins to miter joins for shallow angles.", - "requires": [ - { - "line-join": "round" - } - ] + writeSFixed32Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed32); + this.writeSFixed32(val); }, - "visibility": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "visible", - "none" - ], - "default": "visible", - "doc": "The display of this layer. `none` hides this layer." - } - }, - "layout_symbol": { - "symbol-placement": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "point", - "line" - ], - "default": "point", - "doc": "Label placement relative to its geometry. `line` can only be used on LineStrings and Polygons." - }, - "symbol-spacing": { - "type": "number", - "default": 250, - "minimum": 1, - "function": "interpolated", - "units": "pixels", - "doc": "Distance between two symbol anchors.", - "requires": [ - { - "symbol-placement": "line" - } - ] - }, - "symbol-avoid-edges": { - "type": "boolean", - "function": "piecewise-constant", - "default": false, - "doc": "If true, the symbols will not cross tile edges to avoid mutual collisions. Recommended in layers that don't have enough padding in the vector tile to prevent collisions, or if it is a point symbol layer placed after a line symbol layer." - }, - "icon-allow-overlap": { - "type": "boolean", - "function": "piecewise-constant", - "default": false, - "doc": "If true, the icon will be visible even if it collides with other previously drawn symbols.", - "requires": [ - "icon-image" - ] - }, - "icon-ignore-placement": { - "type": "boolean", - "function": "piecewise-constant", - "default": false, - "doc": "If true, other symbols can be visible even if they collide with the icon.", - "requires": [ - "icon-image" - ] - }, - "icon-optional": { - "type": "boolean", - "function": "piecewise-constant", - "default": false, - "doc": "If true, text will display without their corresponding icons when the icon collides with other symbols and the text does not.", - "requires": [ - "icon-image", - "text-field" - ] - }, - "icon-rotation-alignment": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "map", - "viewport" - ], - "default": "viewport", - "doc": "Orientation of icon when map is rotated.", - "requires": [ - "icon-image" - ] - }, - "icon-size": { - "type": "number", - "default": 1, - "minimum": 0, - "function": "interpolated", - "doc": "Scale factor for icon. 1 is original size, 3 triples the size.", - "requires": [ - "icon-image" - ] - }, - "icon-image": { - "type": "string", - "function": "piecewise-constant", - "doc": "A string with {tokens} replaced, referencing the data property to pull from.", - "tokens": true - }, - "icon-rotate": { - "type": "number", - "default": 0, - "period": 360, - "function": "interpolated", - "units": "degrees", - "doc": "Rotates the icon clockwise.", - "requires": [ - "icon-image" - ] - }, - "icon-padding": { - "type": "number", - "default": 2, - "minimum": 0, - "function": "interpolated", - "units": "pixels", - "doc": "Size of the additional area around the icon bounding box used for detecting symbol collisions.", - "requires": [ - "icon-image" - ] - }, - "icon-keep-upright": { - "type": "boolean", - "function": "piecewise-constant", - "default": false, - "doc": "If true, the icon may be flipped to prevent it from being rendered upside-down.", - "requires": [ - "icon-image", - { - "icon-rotation-alignment": "map" - }, - { - "symbol-placement": "line" - } - ] + writeFixed64Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed64); + this.writeFixed64(val); }, - "icon-offset": { - "type": "array", - "value": "number", - "length": 2, - "default": [ - 0, - 0 - ], - "function": "interpolated", - "doc": "Offset distance of icon from its anchor. Positive values indicate right and down, while negative values indicate left and up.", - "requires": [ - "icon-image" - ] - }, - "text-rotation-alignment": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "map", - "viewport" - ], - "default": "viewport", - "doc": "Orientation of text when map is rotated.", - "requires": [ - "text-field" - ] - }, - "text-field": { - "type": "string", - "function": "piecewise-constant", - "default": "", - "tokens": true, - "doc": "Value to use for a text label. Feature properties are specified using tokens like {field_name}." - }, - "text-font": { - "type": "array", - "value": "string", - "function": "piecewise-constant", - "default": ["Open Sans Regular", "Arial Unicode MS Regular"], - "doc": "Font stack to use for displaying text.", - "requires": [ - "text-field" - ] - }, - "text-size": { - "type": "number", - "default": 16, - "minimum": 0, - "units": "pixels", - "function": "interpolated", - "doc": "Font size.", - "requires": [ - "text-field" - ] - }, - "text-max-width": { - "type": "number", - "default": 10, - "minimum": 0, - "units": "em", - "function": "interpolated", - "doc": "The maximum line width for text wrapping.", - "requires": [ - "text-field" - ] - }, - "text-line-height": { - "type": "number", - "default": 1.2, - "units": "em", - "function": "interpolated", - "doc": "Text leading value for multi-line text.", - "requires": [ - "text-field" - ] - }, - "text-letter-spacing": { - "type": "number", - "default": 0, - "units": "em", - "function": "interpolated", - "doc": "Text tracking amount.", - "requires": [ - "text-field" - ] - }, - "text-justify": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "left", - "center", - "right" - ], - "default": "center", - "doc": "Text justification options.", - "requires": [ - "text-field" - ] - }, - "text-anchor": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "center", - "left", - "right", - "top", - "bottom", - "top-left", - "top-right", - "bottom-left", - "bottom-right" - ], - "default": "center", - "doc": "Part of the text placed closest to the anchor.", - "requires": [ - "text-field" - ] - }, - "text-max-angle": { - "type": "number", - "default": 45, - "units": "degrees", - "function": "interpolated", - "doc": "Maximum angle change between adjacent characters.", - "requires": [ - "text-field", - { - "symbol-placement": "line" - } - ] - }, - "text-rotate": { - "type": "number", - "default": 0, - "period": 360, - "units": "degrees", - "function": "interpolated", - "doc": "Rotates the text clockwise.", - "requires": [ - "text-field" - ] - }, - "text-padding": { - "type": "number", - "default": 2, - "minimum": 0, - "units": "pixels", - "function": "interpolated", - "doc": "Size of the additional area around the text bounding box used for detecting symbol collisions.", - "requires": [ - "text-field" - ] - }, - "text-keep-upright": { - "type": "boolean", - "function": "piecewise-constant", - "default": true, - "doc": "If true, the text may be flipped vertically to prevent it from being rendered upside-down.", - "requires": [ - "text-field", - { - "text-rotation-alignment": "map" - }, - { - "symbol-placement": "line" - } - ] - }, - "text-transform": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "none", - "uppercase", - "lowercase" - ], - "default": "none", - "doc": "Specifies how to capitalize text, similar to the CSS `text-transform` property.", - "requires": [ - "text-field" - ] - }, - "text-offset": { - "type": "array", - "doc": "Offset distance of text from its anchor. Positive values indicate right and down, while negative values indicate left and up.", - "value": "number", - "units": "ems", - "function": "interpolated", - "length": 2, - "default": [ - 0, - 0 - ], - "requires": [ - "text-field" - ] - }, - "text-allow-overlap": { - "type": "boolean", - "function": "piecewise-constant", - "default": false, - "doc": "If true, the text will be visible even if it collides with other previously drawn symbols.", - "requires": [ - "text-field" - ] - }, - "text-ignore-placement": { - "type": "boolean", - "function": "piecewise-constant", - "default": false, - "doc": "If true, other symbols can be visible even if they collide with the text.", - "requires": [ - "text-field" - ] - }, - "text-optional": { - "type": "boolean", - "function": "piecewise-constant", - "default": false, - "doc": "If true, icons will display without their corresponding text when the text collides with other symbols and the icon does not.", - "requires": [ - "text-field", - "icon-image" - ] - }, - "visibility": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "visible", - "none" - ], - "default": "visible", - "doc": "The display of this layer. `none` hides this layer." - } - }, - "layout_raster": { - "visibility": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "visible", - "none" - ], - "default": "visible", - "doc": "The display of this layer. `none` hides this layer." - } - }, - "filter": { - "type": "array", - "value": "*", - "doc": "A filter selects specific features from a layer." - }, - "filter_operator": { - "type": "enum", - "values": [ - "==", - "!=", - ">", - ">=", - "<", - "<=", - "in", - "!in", - "all", - "any", - "none" - ], - "doc": "The filter operator." - }, - "geometry_type": { - "type": "enum", - "values": [ - "Point", - "LineString", - "Polygon" - ], - "doc": "The geometry type for the filter to select." - }, - "color_operation": { - "type": "enum", - "values": [ - "lighten", - "saturate", - "spin", - "fade", - "mix" - ], - "doc": "A color operation to apply." - }, - "function": { - "stops": { - "type": "array", - "required": true, - "doc": "An array of stops.", - "value": "function_stop" - }, - "base": { - "type": "number", - "default": 1, - "minimum": 0, - "doc": "The exponential base of the interpolation curve. It controls the rate at which the result increases. Higher values make the result increase more towards the high end of the range. With `1` the stops are interpolated linearly." - } - }, - "function_stop": { - "type": "array", - "minimum": 0, - "maximum": 22, - "value": [ - "number", - "color" - ], - "length": 2, - "doc": "Zoom level and value pair." - }, - "paint": [ - "paint_fill", - "paint_line", - "paint_circle", - "paint_symbol", - "paint_raster", - "paint_background" - ], - "paint_fill": { - "fill-antialias": { - "type": "boolean", - "function": "piecewise-constant", - "default": true, - "doc": "Whether or not the fill should be antialiased." - }, - "fill-opacity": { - "type": "number", - "function": "interpolated", - "default": 1, - "minimum": 0, - "maximum": 1, - "doc": "The opacity given to the fill color.", - "transition": true - }, - "fill-color": { - "type": "color", - "default": "#000000", - "doc": "The color of the fill.", - "function": "interpolated", - "transition": true, - "requires": [ - { - "!": "fill-pattern" - } - ] + writeSFixed64Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed64); + this.writeSFixed64(val); }, - "fill-outline-color": { - "type": "color", - "doc": "The outline color of the fill. Matches the value of `fill-color` if unspecified.", - "function": "interpolated", - "transition": true, - "requires": [ - { - "!": "fill-pattern" - }, - { - "fill-antialias": true - } - ] + writeVarintField: function(tag, val) { + this.writeTag(tag, Pbf.Varint); + this.writeVarint(val); }, - "fill-translate": { - "type": "array", - "value": "number", - "length": 2, - "default": [ - 0, - 0 - ], - "function": "interpolated", - "transition": true, - "units": "pixels", - "doc": "The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively." - }, - "fill-translate-anchor": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "map", - "viewport" - ], - "doc": "Control whether the translation is relative to the map (north) or viewport (screen)", - "default": "map", - "requires": [ - "fill-translate" - ] - }, - "fill-pattern": { - "type": "string", - "function": "piecewise-constant", - "transition": true, - "doc": "Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512)." - } - }, - "paint_line": { - "line-opacity": { - "type": "number", - "doc": "The opacity at which the line will be drawn.", - "function": "interpolated", - "default": 1, - "minimum": 0, - "maximum": 1, - "transition": true - }, - "line-color": { - "type": "color", - "doc": "The color with which the line will be drawn.", - "default": "#000000", - "function": "interpolated", - "transition": true, - "requires": [ - { - "!": "line-pattern" - } - ] + writeSVarintField: function(tag, val) { + this.writeTag(tag, Pbf.Varint); + this.writeSVarint(val); }, - "line-translate": { - "type": "array", - "value": "number", - "length": 2, - "default": [ - 0, - 0 - ], - "function": "interpolated", - "transition": true, - "units": "pixels", - "doc": "The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively." - }, - "line-translate-anchor": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "map", - "viewport" - ], - "doc": "Control whether the translation is relative to the map (north) or viewport (screen)", - "default": "map", - "requires": [ - "line-translate" - ] - }, - "line-width": { - "type": "number", - "default": 1, - "minimum": 0, - "function": "interpolated", - "transition": true, - "units": "pixels", - "doc": "Stroke thickness." - }, - "line-gap-width": { - "type": "number", - "default": 0, - "minimum": 0, - "doc": "Draws a line casing outside of a line's actual path. Value indicates the width of the inner gap.", - "function": "interpolated", - "transition": true, - "units": "pixels" - }, - "line-offset": { - "type": "number", - "default": 0, - "doc": "The line's offset perpendicular to its direction. Values may be positive or negative, where positive indicates \"rightwards\" (if you were moving in the direction of the line) and negative indicates \"leftwards.\"", - "function": "interpolated", - "transition": true, - "units": "pixels" - }, - "line-blur": { - "type": "number", - "default": 0, - "minimum": 0, - "function": "interpolated", - "transition": true, - "units": "pixels", - "doc": "Blur applied to the line, in pixels." - }, - "line-dasharray": { - "type": "array", - "value": "number", - "function": "piecewise-constant", - "doc": "Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to pixels, multiply the length by the current line width.", - "minimum": 0, - "transition": true, - "units": "line widths", - "requires": [ - { - "!": "line-pattern" - } - ] + writeStringField: function(tag, str) { + this.writeTag(tag, Pbf.Bytes); + this.writeString(str); }, - "line-pattern": { - "type": "string", - "function": "piecewise-constant", - "transition": true, - "doc": "Name of image in sprite to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512)." - } - }, - "paint_circle": { - "circle-radius": { - "type": "number", - "default": 5, - "minimum": 0, - "function": "interpolated", - "transition": true, - "units": "pixels", - "doc": "Circle radius." - }, - "circle-color": { - "type": "color", - "default": "#000000", - "doc": "The color of the circle.", - "function": "interpolated", - "transition": true - }, - "circle-blur": { - "type": "number", - "default": 0, - "doc": "Amount to blur the circle. 1 blurs the circle such that only the centerpoint is full opacity.", - "function": "interpolated", - "transition": true - }, - "circle-opacity": { - "type": "number", - "doc": "The opacity at which the circle will be drawn.", - "default": 1, - "minimum": 0, - "maximum": 1, - "function": "interpolated", - "transition": true - }, - "circle-translate": { - "type": "array", - "value": "number", - "length": 2, - "default": [0, 0], - "function": "interpolated", - "transition": true, - "units": "pixels", - "doc": "The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively." - }, - "circle-translate-anchor": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "map", - "viewport" - ], - "doc": "Control whether the translation is relative to the map (north) or viewport (screen)", - "default": "map", - "requires": [ - "circle-translate" - ] - } - }, - "paint_symbol": { - "icon-opacity": { - "doc": "The opacity at which the icon will be drawn.", - "type": "number", - "default": 1, - "minimum": 0, - "maximum": 1, - "function": "interpolated", - "transition": true, - "requires": [ - "icon-image" - ] - }, - "icon-color": { - "type": "color", - "default": "#000000", - "function": "interpolated", - "transition": true, - "doc": "The color of the icon. This can only be used with sdf icons.", - "requires": [ - "icon-image" - ] - }, - "icon-halo-color": { - "type": "color", - "default": "rgba(0, 0, 0, 0)", - "function": "interpolated", - "transition": true, - "doc": "The color of the icon's halo. Icon halos can only be used with sdf icons.", - "requires": [ - "icon-image" - ] - }, - "icon-halo-width": { - "type": "number", - "default": 0, - "minimum": 0, - "function": "interpolated", - "transition": true, - "units": "pixels", - "doc": "Distance of halo to the icon outline.", - "requires": [ - "icon-image" - ] - }, - "icon-halo-blur": { - "type": "number", - "default": 0, - "minimum": 0, - "function": "interpolated", - "transition": true, - "units": "pixels", - "doc": "Fade out the halo towards the outside.", - "requires": [ - "icon-image" - ] - }, - "icon-translate": { - "type": "array", - "value": "number", - "length": 2, - "default": [ - 0, - 0 - ], - "function": "interpolated", - "transition": true, - "units": "pixels", - "doc": "Distance that the icon's anchor is moved from its original placement. Positive values indicate right and down, while negative values indicate left and up.", - "requires": [ - "icon-image" - ] - }, - "icon-translate-anchor": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "map", - "viewport" - ], - "doc": "Control whether the translation is relative to the map (north) or viewport (screen).", - "default": "map", - "requires": [ - "icon-image", - "icon-translate" - ] - }, - "text-opacity": { - "type": "number", - "doc": "The opacity at which the text will be drawn.", - "default": 1, - "minimum": 0, - "maximum": 1, - "function": "interpolated", - "transition": true, - "requires": [ - "text-field" - ] - }, - "text-color": { - "type": "color", - "doc": "The color with which the text will be drawn.", - "default": "#000000", - "function": "interpolated", - "transition": true, - "requires": [ - "text-field" - ] - }, - "text-halo-color": { - "type": "color", - "default": "rgba(0, 0, 0, 0)", - "function": "interpolated", - "transition": true, - "doc": "The color of the text's halo, which helps it stand out from backgrounds.", - "requires": [ - "text-field" - ] - }, - "text-halo-width": { - "type": "number", - "default": 0, - "minimum": 0, - "function": "interpolated", - "transition": true, - "units": "pixels", - "doc": "Distance of halo to the font outline. Max text halo width is 1/4 of the font-size.", - "requires": [ - "text-field" - ] - }, - "text-halo-blur": { - "type": "number", - "default": 0, - "minimum": 0, - "function": "interpolated", - "transition": true, - "units": "pixels", - "doc": "The halo's fadeout distance towards the outside.", - "requires": [ - "text-field" - ] - }, - "text-translate": { - "type": "array", - "value": "number", - "length": 2, - "default": [ - 0, - 0 - ], - "function": "interpolated", - "transition": true, - "units": "pixels", - "doc": "Distance that the text's anchor is moved from its original placement. Positive values indicate right and down, while negative values indicate left and up.", - "requires": [ - "text-field" - ] - }, - "text-translate-anchor": { - "type": "enum", - "function": "piecewise-constant", - "values": [ - "map", - "viewport" - ], - "doc": "Control whether the translation is relative to the map (north) or viewport (screen).", - "default": "map", - "requires": [ - "text-field", - "text-translate" - ] - } - }, - "paint_raster": { - "raster-opacity": { - "type": "number", - "doc": "The opacity at which the image will be drawn.", - "default": 1, - "minimum": 0, - "maximum": 1, - "function": "interpolated", - "transition": true - }, - "raster-hue-rotate": { - "type": "number", - "default": 0, - "period": 360, - "function": "interpolated", - "transition": true, - "units": "degrees", - "doc": "Rotates hues around the color wheel." - }, - "raster-brightness-min": { - "type": "number", - "function": "interpolated", - "doc": "Increase or reduce the brightness of the image. The value is the minimum brightness.", - "default": 0, - "minimum": 0, - "maximum": 1, - "transition": true - }, - "raster-brightness-max": { - "type": "number", - "function": "interpolated", - "doc": "Increase or reduce the brightness of the image. The value is the maximum brightness.", - "default": 1, - "minimum": 0, - "maximum": 1, - "transition": true - }, - "raster-saturation": { - "type": "number", - "doc": "Increase or reduce the saturation of the image.", - "default": 0, - "minimum": -1, - "maximum": 1, - "function": "interpolated", - "transition": true - }, - "raster-contrast": { - "type": "number", - "doc": "Increase or reduce the contrast of the image.", - "default": 0, - "minimum": -1, - "maximum": 1, - "function": "interpolated", - "transition": true - }, - "raster-fade-duration": { - "type": "number", - "default": 300, - "minimum": 0, - "function": "interpolated", - "transition": true, - "units": "milliseconds", - "doc": "Fade duration when a new tile is added." - } - }, - "paint_background": { - "background-color": { - "type": "color", - "default": "#000000", - "doc": "The color with which the background will be drawn.", - "function": "interpolated", - "transition": true, - "requires": [ - { - "!": "background-pattern" - } - ] + writeFloatField: function(tag, val) { + this.writeTag(tag, Pbf.Fixed32); + this.writeFloat(val); }, - "background-pattern": { - "type": "string", - "function": "piecewise-constant", - "transition": true, - "doc": "Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512)." + writeDoubleField: function(tag, val) { + this.writeTag(tag, Pbf.Fixed64); + this.writeDouble(val); }, - "background-opacity": { - "type": "number", - "default": 1, - "minimum": 0, - "maximum": 1, - "doc": "The opacity at which the background will be drawn.", - "function": "interpolated", - "transition": true - } - }, - "transition": { - "duration": { - "type": "number", - "default": 300, - "minimum": 0, - "units": "milliseconds", - "doc": "Time allotted for transitions to complete." - }, - "delay": { - "type": "number", - "default": 0, - "minimum": 0, - "units": "milliseconds", - "doc": "Length of time before a transition begins." + writeBooleanField: function(tag, val) { + this.writeVarintField(tag, Boolean(val)); } - } +}; + +function readVarintRemainder(l, s, p) { + var buf = p.buf, + h, b; + + b = buf[p.pos++]; h = (b & 0x70) >> 4; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x7f) << 3; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x7f) << 10; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x7f) << 17; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x7f) << 24; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x01) << 31; if (b < 0x80) return toNum(l, h, s); + + throw new Error('Expected varint not more than 10 bytes'); } -},{}],158:[function(require,module,exports){ -module.exports={"$version":8,"$root":{"version":{"required":true,"type":"enum","values":[8]},"name":{"type":"string"},"metadata":{"type":"*"},"center":{"type":"array","value":"number"},"zoom":{"type":"number"},"bearing":{"type":"number","default":0,"period":360,"units":"degrees"},"pitch":{"type":"number","default":0,"units":"degrees"},"sources":{"required":true,"type":"sources"},"sprite":{"type":"string"},"glyphs":{"type":"string"},"transition":{"type":"transition"},"layers":{"required":true,"type":"array","value":"layer"}},"sources":{"*":{"type":"source"}},"source":["source_tile","source_geojson","source_video","source_image"],"source_tile":{"type":{"required":true,"type":"enum","values":["vector","raster"]},"url":{"type":"string"},"tiles":{"type":"array","value":"string"},"minzoom":{"type":"number","default":0},"maxzoom":{"type":"number","default":22},"tileSize":{"type":"number","default":512,"units":"pixels"},"*":{"type":"*"}},"source_geojson":{"type":{"required":true,"type":"enum","values":["geojson"]},"data":{"type":"*"},"maxzoom":{"type":"number","default":14},"buffer":{"type":"number","default":64},"tolerance":{"type":"number","default":3},"cluster":{"type":"boolean","default":false},"clusterRadius":{"type":"number","default":400},"clusterMaxZoom":{"type":"number"}},"source_video":{"type":{"required":true,"type":"enum","values":["video"]},"urls":{"required":true,"type":"array","value":"string"},"coordinates":{"required":true,"type":"array","length":4,"value":{"type":"array","length":2,"value":"number"}}},"source_image":{"type":{"required":true,"type":"enum","values":["image"]},"url":{"required":true,"type":"string"},"coordinates":{"required":true,"type":"array","length":4,"value":{"type":"array","length":2,"value":"number"}}},"layer":{"id":{"type":"string","required":true},"type":{"type":"enum","values":["fill","line","symbol","circle","raster","background"]},"metadata":{"type":"*"},"ref":{"type":"string"},"source":{"type":"string"},"source-layer":{"type":"string"},"minzoom":{"type":"number","minimum":0,"maximum":22},"maxzoom":{"type":"number","minimum":0,"maximum":22},"interactive":{"type":"boolean","default":false},"filter":{"type":"filter"},"layout":{"type":"layout"},"paint":{"type":"paint"},"paint.*":{"type":"paint"}},"layout":["layout_fill","layout_line","layout_circle","layout_symbol","layout_raster","layout_background"],"layout_background":{"visibility":{"type":"enum","function":"piecewise-constant","values":["visible","none"],"default":"visible"}},"layout_fill":{"visibility":{"type":"enum","function":"piecewise-constant","values":["visible","none"],"default":"visible"}},"layout_circle":{"visibility":{"type":"enum","function":"piecewise-constant","values":["visible","none"],"default":"visible"}},"layout_line":{"line-cap":{"type":"enum","function":"piecewise-constant","values":["butt","round","square"],"default":"butt"},"line-join":{"type":"enum","function":"piecewise-constant","values":["bevel","round","miter"],"default":"miter"},"line-miter-limit":{"type":"number","default":2,"function":"interpolated","requires":[{"line-join":"miter"}]},"line-round-limit":{"type":"number","default":1.05,"function":"interpolated","requires":[{"line-join":"round"}]},"visibility":{"type":"enum","function":"piecewise-constant","values":["visible","none"],"default":"visible"}},"layout_symbol":{"symbol-placement":{"type":"enum","function":"piecewise-constant","values":["point","line"],"default":"point"},"symbol-spacing":{"type":"number","default":250,"minimum":1,"function":"interpolated","units":"pixels","requires":[{"symbol-placement":"line"}]},"symbol-avoid-edges":{"type":"boolean","function":"piecewise-constant","default":false},"icon-allow-overlap":{"type":"boolean","function":"piecewise-constant","default":false,"requires":["icon-image"]},"icon-ignore-placement":{"type":"boolean","function":"piecewise-constant","default":false,"requires":["icon-image"]},"icon-optional":{"type":"boolean","function":"piecewise-constant","default":false,"requires":["icon-image","text-field"]},"icon-rotation-alignment":{"type":"enum","function":"piecewise-constant","values":["map","viewport"],"default":"viewport","requires":["icon-image"]},"icon-size":{"type":"number","default":1,"minimum":0,"function":"interpolated","requires":["icon-image"]},"icon-image":{"type":"string","function":"piecewise-constant","tokens":true},"icon-rotate":{"type":"number","default":0,"period":360,"function":"interpolated","units":"degrees","requires":["icon-image"]},"icon-padding":{"type":"number","default":2,"minimum":0,"function":"interpolated","units":"pixels","requires":["icon-image"]},"icon-keep-upright":{"type":"boolean","function":"piecewise-constant","default":false,"requires":["icon-image",{"icon-rotation-alignment":"map"},{"symbol-placement":"line"}]},"icon-offset":{"type":"array","value":"number","length":2,"default":[0,0],"function":"interpolated","requires":["icon-image"]},"text-rotation-alignment":{"type":"enum","function":"piecewise-constant","values":["map","viewport"],"default":"viewport","requires":["text-field"]},"text-field":{"type":"string","function":"piecewise-constant","default":"","tokens":true},"text-font":{"type":"array","value":"string","function":"piecewise-constant","default":["Open Sans Regular","Arial Unicode MS Regular"],"requires":["text-field"]},"text-size":{"type":"number","default":16,"minimum":0,"units":"pixels","function":"interpolated","requires":["text-field"]},"text-max-width":{"type":"number","default":10,"minimum":0,"units":"em","function":"interpolated","requires":["text-field"]},"text-line-height":{"type":"number","default":1.2,"units":"em","function":"interpolated","requires":["text-field"]},"text-letter-spacing":{"type":"number","default":0,"units":"em","function":"interpolated","requires":["text-field"]},"text-justify":{"type":"enum","function":"piecewise-constant","values":["left","center","right"],"default":"center","requires":["text-field"]},"text-anchor":{"type":"enum","function":"piecewise-constant","values":["center","left","right","top","bottom","top-left","top-right","bottom-left","bottom-right"],"default":"center","requires":["text-field"]},"text-max-angle":{"type":"number","default":45,"units":"degrees","function":"interpolated","requires":["text-field",{"symbol-placement":"line"}]},"text-rotate":{"type":"number","default":0,"period":360,"units":"degrees","function":"interpolated","requires":["text-field"]},"text-padding":{"type":"number","default":2,"minimum":0,"units":"pixels","function":"interpolated","requires":["text-field"]},"text-keep-upright":{"type":"boolean","function":"piecewise-constant","default":true,"requires":["text-field",{"text-rotation-alignment":"map"},{"symbol-placement":"line"}]},"text-transform":{"type":"enum","function":"piecewise-constant","values":["none","uppercase","lowercase"],"default":"none","requires":["text-field"]},"text-offset":{"type":"array","value":"number","units":"ems","function":"interpolated","length":2,"default":[0,0],"requires":["text-field"]},"text-allow-overlap":{"type":"boolean","function":"piecewise-constant","default":false,"requires":["text-field"]},"text-ignore-placement":{"type":"boolean","function":"piecewise-constant","default":false,"requires":["text-field"]},"text-optional":{"type":"boolean","function":"piecewise-constant","default":false,"requires":["text-field","icon-image"]},"visibility":{"type":"enum","function":"piecewise-constant","values":["visible","none"],"default":"visible"}},"layout_raster":{"visibility":{"type":"enum","function":"piecewise-constant","values":["visible","none"],"default":"visible"}},"filter":{"type":"array","value":"*"},"filter_operator":{"type":"enum","values":["==","!=",">",">=","<","<=","in","!in","all","any","none"]},"geometry_type":{"type":"enum","values":["Point","LineString","Polygon"]},"color_operation":{"type":"enum","values":["lighten","saturate","spin","fade","mix"]},"function":{"stops":{"type":"array","required":true,"value":"function_stop"},"base":{"type":"number","default":1,"minimum":0}},"function_stop":{"type":"array","minimum":0,"maximum":22,"value":["number","color"],"length":2},"paint":["paint_fill","paint_line","paint_circle","paint_symbol","paint_raster","paint_background"],"paint_fill":{"fill-antialias":{"type":"boolean","function":"piecewise-constant","default":true},"fill-opacity":{"type":"number","function":"interpolated","default":1,"minimum":0,"maximum":1,"transition":true},"fill-color":{"type":"color","default":"#000000","function":"interpolated","transition":true,"requires":[{"!":"fill-pattern"}]},"fill-outline-color":{"type":"color","function":"interpolated","transition":true,"requires":[{"!":"fill-pattern"},{"fill-antialias":true}]},"fill-translate":{"type":"array","value":"number","length":2,"default":[0,0],"function":"interpolated","transition":true,"units":"pixels"},"fill-translate-anchor":{"type":"enum","function":"piecewise-constant","values":["map","viewport"],"default":"map","requires":["fill-translate"]},"fill-pattern":{"type":"string","function":"piecewise-constant","transition":true}},"paint_line":{"line-opacity":{"type":"number","function":"interpolated","default":1,"minimum":0,"maximum":1,"transition":true},"line-color":{"type":"color","default":"#000000","function":"interpolated","transition":true,"requires":[{"!":"line-pattern"}]},"line-translate":{"type":"array","value":"number","length":2,"default":[0,0],"function":"interpolated","transition":true,"units":"pixels"},"line-translate-anchor":{"type":"enum","function":"piecewise-constant","values":["map","viewport"],"default":"map","requires":["line-translate"]},"line-width":{"type":"number","default":1,"minimum":0,"function":"interpolated","transition":true,"units":"pixels"},"line-gap-width":{"type":"number","default":0,"minimum":0,"function":"interpolated","transition":true,"units":"pixels"},"line-offset":{"type":"number","default":0,"function":"interpolated","transition":true,"units":"pixels"},"line-blur":{"type":"number","default":0,"minimum":0,"function":"interpolated","transition":true,"units":"pixels"},"line-dasharray":{"type":"array","value":"number","function":"piecewise-constant","minimum":0,"transition":true,"units":"line widths","requires":[{"!":"line-pattern"}]},"line-pattern":{"type":"string","function":"piecewise-constant","transition":true}},"paint_circle":{"circle-radius":{"type":"number","default":5,"minimum":0,"function":"interpolated","transition":true,"units":"pixels"},"circle-color":{"type":"color","default":"#000000","function":"interpolated","transition":true},"circle-blur":{"type":"number","default":0,"function":"interpolated","transition":true},"circle-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"function":"interpolated","transition":true},"circle-translate":{"type":"array","value":"number","length":2,"default":[0,0],"function":"interpolated","transition":true,"units":"pixels"},"circle-translate-anchor":{"type":"enum","function":"piecewise-constant","values":["map","viewport"],"default":"map","requires":["circle-translate"]}},"paint_symbol":{"icon-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"function":"interpolated","transition":true,"requires":["icon-image"]},"icon-color":{"type":"color","default":"#000000","function":"interpolated","transition":true,"requires":["icon-image"]},"icon-halo-color":{"type":"color","default":"rgba(0, 0, 0, 0)","function":"interpolated","transition":true,"requires":["icon-image"]},"icon-halo-width":{"type":"number","default":0,"minimum":0,"function":"interpolated","transition":true,"units":"pixels","requires":["icon-image"]},"icon-halo-blur":{"type":"number","default":0,"minimum":0,"function":"interpolated","transition":true,"units":"pixels","requires":["icon-image"]},"icon-translate":{"type":"array","value":"number","length":2,"default":[0,0],"function":"interpolated","transition":true,"units":"pixels","requires":["icon-image"]},"icon-translate-anchor":{"type":"enum","function":"piecewise-constant","values":["map","viewport"],"default":"map","requires":["icon-image","icon-translate"]},"text-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"function":"interpolated","transition":true,"requires":["text-field"]},"text-color":{"type":"color","default":"#000000","function":"interpolated","transition":true,"requires":["text-field"]},"text-halo-color":{"type":"color","default":"rgba(0, 0, 0, 0)","function":"interpolated","transition":true,"requires":["text-field"]},"text-halo-width":{"type":"number","default":0,"minimum":0,"function":"interpolated","transition":true,"units":"pixels","requires":["text-field"]},"text-halo-blur":{"type":"number","default":0,"minimum":0,"function":"interpolated","transition":true,"units":"pixels","requires":["text-field"]},"text-translate":{"type":"array","value":"number","length":2,"default":[0,0],"function":"interpolated","transition":true,"units":"pixels","requires":["text-field"]},"text-translate-anchor":{"type":"enum","function":"piecewise-constant","values":["map","viewport"],"default":"map","requires":["text-field","text-translate"]}},"paint_raster":{"raster-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"function":"interpolated","transition":true},"raster-hue-rotate":{"type":"number","default":0,"period":360,"function":"interpolated","transition":true,"units":"degrees"},"raster-brightness-min":{"type":"number","function":"interpolated","default":0,"minimum":0,"maximum":1,"transition":true},"raster-brightness-max":{"type":"number","function":"interpolated","default":1,"minimum":0,"maximum":1,"transition":true},"raster-saturation":{"type":"number","default":0,"minimum":-1,"maximum":1,"function":"interpolated","transition":true},"raster-contrast":{"type":"number","default":0,"minimum":-1,"maximum":1,"function":"interpolated","transition":true},"raster-fade-duration":{"type":"number","default":300,"minimum":0,"function":"interpolated","transition":true,"units":"milliseconds"}},"paint_background":{"background-color":{"type":"color","default":"#000000","function":"interpolated","transition":true,"requires":[{"!":"background-pattern"}]},"background-pattern":{"type":"string","function":"piecewise-constant","transition":true},"background-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"function":"interpolated","transition":true}},"transition":{"duration":{"type":"number","default":300,"minimum":0,"units":"milliseconds"},"delay":{"type":"number","default":0,"minimum":0,"units":"milliseconds"}}} -},{}],159:[function(require,module,exports){ -'use strict'; +function readPackedEnd(pbf) { + return pbf.type === Pbf.Bytes ? + pbf.readVarint() + pbf.pos : pbf.pos + 1; +} -// lightweight Buffer shim for pbf browser build -// based on code from github.com/feross/buffer (MIT-licensed) +function toNum(low, high, isSigned) { + if (isSigned) { + return high * 0x100000000 + (low >>> 0); + } -module.exports = Buffer; + return ((high >>> 0) * 0x100000000) + (low >>> 0); +} -var ieee754 = require('ieee754'); +function writeBigVarint(val, pbf) { + var low, high; -var BufferMethods; + if (val >= 0) { + low = (val % 0x100000000) | 0; + high = (val / 0x100000000) | 0; + } else { + low = ~(-val % 0x100000000); + high = ~(-val / 0x100000000); -function Buffer(length) { - var arr; - if (length && length.length) { - arr = length; - length = arr.length; + if (low ^ 0xffffffff) { + low = (low + 1) | 0; + } else { + low = 0; + high = (high + 1) | 0; + } } - var buf = new Uint8Array(length || 0); - if (arr) buf.set(arr); - buf.readUInt32LE = BufferMethods.readUInt32LE; - buf.writeUInt32LE = BufferMethods.writeUInt32LE; - buf.readInt32LE = BufferMethods.readInt32LE; - buf.writeInt32LE = BufferMethods.writeInt32LE; - buf.readFloatLE = BufferMethods.readFloatLE; - buf.writeFloatLE = BufferMethods.writeFloatLE; - buf.readDoubleLE = BufferMethods.readDoubleLE; - buf.writeDoubleLE = BufferMethods.writeDoubleLE; - buf.toString = BufferMethods.toString; - buf.write = BufferMethods.write; - buf.slice = BufferMethods.slice; - buf.copy = BufferMethods.copy; + if (val >= 0x10000000000000000 || val < -0x10000000000000000) { + throw new Error('Given varint doesn\'t fit into 10 bytes'); + } - buf._isBuffer = true; - return buf; -} + pbf.realloc(10); -var lastStr, lastStrEncoded; + writeBigVarintLow(low, high, pbf); + writeBigVarintHigh(high, pbf); +} -BufferMethods = { - readUInt32LE: function(pos) { - return ((this[pos]) | - (this[pos + 1] << 8) | - (this[pos + 2] << 16)) + - (this[pos + 3] * 0x1000000); - }, +function writeBigVarintLow(low, high, pbf) { + pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; + pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; + pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; + pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; + pbf.buf[pbf.pos] = low & 0x7f; +} - writeUInt32LE: function(val, pos) { - this[pos] = val; - this[pos + 1] = (val >>> 8); - this[pos + 2] = (val >>> 16); - this[pos + 3] = (val >>> 24); - }, +function writeBigVarintHigh(high, pbf) { + var lsb = (high & 0x07) << 4; - readInt32LE: function(pos) { - return ((this[pos]) | - (this[pos + 1] << 8) | - (this[pos + 2] << 16)) + - (this[pos + 3] << 24); - }, + pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f; +} - readFloatLE: function(pos) { return ieee754.read(this, pos, true, 23, 4); }, - readDoubleLE: function(pos) { return ieee754.read(this, pos, true, 52, 8); }, +function makeRoomForExtraLength(startPos, len, pbf) { + var extraLen = + len <= 0x3fff ? 1 : + len <= 0x1fffff ? 2 : + len <= 0xfffffff ? 3 : Math.ceil(Math.log(len) / (Math.LN2 * 7)); - writeFloatLE: function(val, pos) { return ieee754.write(this, val, pos, true, 23, 4); }, - writeDoubleLE: function(val, pos) { return ieee754.write(this, val, pos, true, 52, 8); }, + // if 1 byte isn't enough for encoding message length, shift the data to the right + pbf.realloc(extraLen); + for (var i = pbf.pos - 1; i >= startPos; i--) pbf.buf[i + extraLen] = pbf.buf[i]; +} - toString: function(encoding, start, end) { - var str = '', - tmp = ''; +function writePackedVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]); } +function writePackedSVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]); } +function writePackedFloat(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]); } +function writePackedDouble(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]); } +function writePackedBoolean(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]); } +function writePackedFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]); } +function writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); } +function writePackedFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]); } +function writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); } - start = start || 0; - end = Math.min(this.length, end || this.length); +// Buffer code below from https://github.com/feross/buffer, MIT-licensed - for (var i = start; i < end; i++) { - var ch = this[i]; - if (ch <= 0x7F) { - str += decodeURIComponent(tmp) + String.fromCharCode(ch); - tmp = ''; - } else { - tmp += '%' + ch.toString(16); - } - } +function readUInt32(buf, pos) { + return ((buf[pos]) | + (buf[pos + 1] << 8) | + (buf[pos + 2] << 16)) + + (buf[pos + 3] * 0x1000000); +} - str += decodeURIComponent(tmp); +function writeInt32(buf, val, pos) { + buf[pos] = val; + buf[pos + 1] = (val >>> 8); + buf[pos + 2] = (val >>> 16); + buf[pos + 3] = (val >>> 24); +} - return str; - }, +function readInt32(buf, pos) { + return ((buf[pos]) | + (buf[pos + 1] << 8) | + (buf[pos + 2] << 16)) + + (buf[pos + 3] << 24); +} - write: function(str, pos) { - var bytes = str === lastStr ? lastStrEncoded : encodeString(str); - for (var i = 0; i < bytes.length; i++) { - this[pos + i] = bytes[i]; - } - }, +function readUtf8(buf, pos, end) { + var str = ''; + var i = pos; - slice: function(start, end) { - return this.subarray(start, end); - }, + while (i < end) { + var b0 = buf[i]; + var c = null; // codepoint + var bytesPerSequence = + b0 > 0xEF ? 4 : + b0 > 0xDF ? 3 : + b0 > 0xBF ? 2 : 1; - copy: function(buf, pos) { - pos = pos || 0; - for (var i = 0; i < this.length; i++) { - buf[pos + i] = this[i]; + if (i + bytesPerSequence > end) break; + + var b1, b2, b3; + + if (bytesPerSequence === 1) { + if (b0 < 0x80) { + c = b0; + } + } else if (bytesPerSequence === 2) { + b1 = buf[i + 1]; + if ((b1 & 0xC0) === 0x80) { + c = (b0 & 0x1F) << 0x6 | (b1 & 0x3F); + if (c <= 0x7F) { + c = null; + } + } + } else if (bytesPerSequence === 3) { + b1 = buf[i + 1]; + b2 = buf[i + 2]; + if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) { + c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | (b2 & 0x3F); + if (c <= 0x7FF || (c >= 0xD800 && c <= 0xDFFF)) { + c = null; + } + } + } else if (bytesPerSequence === 4) { + b1 = buf[i + 1]; + b2 = buf[i + 2]; + b3 = buf[i + 3]; + if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) { + c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | (b3 & 0x3F); + if (c <= 0xFFFF || c >= 0x110000) { + c = null; + } + } } - } -}; -BufferMethods.writeInt32LE = BufferMethods.writeUInt32LE; + if (c === null) { + c = 0xFFFD; + bytesPerSequence = 1; -Buffer.byteLength = function(str) { - lastStr = str; - lastStrEncoded = encodeString(str); - return lastStrEncoded.length; -}; + } else if (c > 0xFFFF) { + c -= 0x10000; + str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800); + c = 0xDC00 | c & 0x3FF; + } -Buffer.isBuffer = function(buf) { - return !!(buf && buf._isBuffer); -}; + str += String.fromCharCode(c); + i += bytesPerSequence; + } -function encodeString(str) { - var length = str.length, - bytes = []; + return str; +} - for (var i = 0, c, lead; i < length; i++) { +function writeUtf8(buf, str, pos) { + for (var i = 0, c, lead; i < str.length; i++) { c = str.charCodeAt(i); // code point if (c > 0xD7FF && c < 0xE000) { - if (lead) { if (c < 0xDC00) { - bytes.push(0xEF, 0xBF, 0xBD); + buf[pos++] = 0xEF; + buf[pos++] = 0xBF; + buf[pos++] = 0xBD; lead = c; continue; - } else { c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000; lead = null; } - } else { - if (c > 0xDBFF || (i + 1 === length)) bytes.push(0xEF, 0xBF, 0xBD); - else lead = c; - + if (c > 0xDBFF || (i + 1 === str.length)) { + buf[pos++] = 0xEF; + buf[pos++] = 0xBF; + buf[pos++] = 0xBD; + } else { + lead = c; + } continue; } - } else if (lead) { - bytes.push(0xEF, 0xBF, 0xBD); + buf[pos++] = 0xEF; + buf[pos++] = 0xBF; + buf[pos++] = 0xBD; lead = null; } - if (c < 0x80) bytes.push(c); - else if (c < 0x800) bytes.push(c >> 0x6 | 0xC0, c & 0x3F | 0x80); - else if (c < 0x10000) bytes.push(c >> 0xC | 0xE0, c >> 0x6 & 0x3F | 0x80, c & 0x3F | 0x80); - else bytes.push(c >> 0x12 | 0xF0, c >> 0xC & 0x3F | 0x80, c >> 0x6 & 0x3F | 0x80, c & 0x3F | 0x80); + if (c < 0x80) { + buf[pos++] = c; + } else { + if (c < 0x800) { + buf[pos++] = c >> 0x6 | 0xC0; + } else { + if (c < 0x10000) { + buf[pos++] = c >> 0xC | 0xE0; + } else { + buf[pos++] = c >> 0x12 | 0xF0; + buf[pos++] = c >> 0xC & 0x3F | 0x80; + } + buf[pos++] = c >> 0x6 & 0x3F | 0x80; + } + buf[pos++] = c & 0x3F | 0x80; + } } - return bytes; + return pos; } -},{"ieee754":161}],160:[function(require,module,exports){ -(function (global){ +},{"ieee754":40}],196:[function(require,module,exports){ 'use strict'; -module.exports = Pbf; - -var Buffer = global.Buffer || require('./buffer'); +module.exports = Point; -function Pbf(buf) { - this.buf = !Buffer.isBuffer(buf) ? new Buffer(buf || 0) : buf; - this.pos = 0; - this.length = this.buf.length; +function Point(x, y) { + this.x = x; + this.y = y; } -Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum -Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64 -Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields -Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32 +Point.prototype = { + clone: function() { return new Point(this.x, this.y); }, -var SHIFT_LEFT_32 = (1 << 16) * (1 << 16), - SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32, - POW_2_63 = Math.pow(2, 63); + add: function(p) { return this.clone()._add(p); }, + sub: function(p) { return this.clone()._sub(p); }, + mult: function(k) { return this.clone()._mult(k); }, + div: function(k) { return this.clone()._div(k); }, + rotate: function(a) { return this.clone()._rotate(a); }, + matMult: function(m) { return this.clone()._matMult(m); }, + unit: function() { return this.clone()._unit(); }, + perp: function() { return this.clone()._perp(); }, + round: function() { return this.clone()._round(); }, -Pbf.prototype = { + mag: function() { + return Math.sqrt(this.x * this.x + this.y * this.y); + }, - destroy: function() { - this.buf = null; + equals: function(p) { + return this.x === p.x && + this.y === p.y; }, - // === READING ================================================================= + dist: function(p) { + return Math.sqrt(this.distSqr(p)); + }, - readFields: function(readField, result, end) { - end = end || this.length; + distSqr: function(p) { + var dx = p.x - this.x, + dy = p.y - this.y; + return dx * dx + dy * dy; + }, - while (this.pos < end) { - var val = this.readVarint(), - tag = val >> 3, - startPos = this.pos; + angle: function() { + return Math.atan2(this.y, this.x); + }, - readField(tag, result, this); + angleTo: function(b) { + return Math.atan2(this.y - b.y, this.x - b.x); + }, - if (this.pos === startPos) this.skip(val); - } - return result; + angleWith: function(b) { + return this.angleWithSep(b.x, b.y); }, - readMessage: function(readField, result) { - return this.readFields(readField, result, this.readVarint() + this.pos); + // Find the angle of the two vectors, solving the formula for the cross product a x b = |a||b|sin(θ) for θ. + angleWithSep: function(x, y) { + return Math.atan2( + this.x * y - this.y * x, + this.x * x + this.y * y); }, - readFixed32: function() { - var val = this.buf.readUInt32LE(this.pos); - this.pos += 4; - return val; + _matMult: function(m) { + var x = m[0] * this.x + m[1] * this.y, + y = m[2] * this.x + m[3] * this.y; + this.x = x; + this.y = y; + return this; }, - readSFixed32: function() { - var val = this.buf.readInt32LE(this.pos); - this.pos += 4; - return val; + _add: function(p) { + this.x += p.x; + this.y += p.y; + return this; }, - // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed) + _sub: function(p) { + this.x -= p.x; + this.y -= p.y; + return this; + }, - readFixed64: function() { - var val = this.buf.readUInt32LE(this.pos) + this.buf.readUInt32LE(this.pos + 4) * SHIFT_LEFT_32; - this.pos += 8; - return val; + _mult: function(k) { + this.x *= k; + this.y *= k; + return this; }, - readSFixed64: function() { - var val = this.buf.readUInt32LE(this.pos) + this.buf.readInt32LE(this.pos + 4) * SHIFT_LEFT_32; - this.pos += 8; - return val; + _div: function(k) { + this.x /= k; + this.y /= k; + return this; }, - readFloat: function() { - var val = this.buf.readFloatLE(this.pos); - this.pos += 4; - return val; + _unit: function() { + this._div(this.mag()); + return this; }, - readDouble: function() { - var val = this.buf.readDoubleLE(this.pos); - this.pos += 8; - return val; + _perp: function() { + var y = this.y; + this.y = this.x; + this.x = -y; + return this; }, - readVarint: function() { - var buf = this.buf, - val, b, b0, b1, b2, b3; + _rotate: function(angle) { + var cos = Math.cos(angle), + sin = Math.sin(angle), + x = cos * this.x - sin * this.y, + y = sin * this.x + cos * this.y; + this.x = x; + this.y = y; + return this; + }, + + _round: function() { + this.x = Math.round(this.x); + this.y = Math.round(this.y); + return this; + } +}; + +// constructs Point from an array if necessary +Point.convert = function (a) { + if (a instanceof Point) { + return a; + } + if (Array.isArray(a)) { + return new Point(a[0], a[1]); + } + return a; +}; + +},{}],197:[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; - b0 = buf[this.pos++]; if (b0 < 0x80) return b0; b0 = b0 & 0x7f; - b1 = buf[this.pos++]; if (b1 < 0x80) return b0 | b1 << 7; b1 = (b1 & 0x7f) << 7; - b2 = buf[this.pos++]; if (b2 < 0x80) return b0 | b1 | b2 << 14; b2 = (b2 & 0x7f) << 14; - b3 = buf[this.pos++]; if (b3 < 0x80) return b0 | b1 | b2 | b3 << 21; +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} - val = b0 | b1 | b2 | (b3 & 0x7f) << 21; +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; - b = buf[this.pos++]; val += (b & 0x7f) * 0x10000000; if (b < 0x80) return val; - b = buf[this.pos++]; val += (b & 0x7f) * 0x800000000; if (b < 0x80) return val; - b = buf[this.pos++]; val += (b & 0x7f) * 0x40000000000; if (b < 0x80) return val; - b = buf[this.pos++]; val += (b & 0x7f) * 0x2000000000000; if (b < 0x80) return val; - b = buf[this.pos++]; val += (b & 0x7f) * 0x100000000000000; if (b < 0x80) return val; - b = buf[this.pos++]; val += (b & 0x7f) * 0x8000000000000000; if (b < 0x80) return val; + 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); +} - throw new Error('Expected varint not more than 10 bytes'); - }, +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); + } +}; - readVarint64: function() { - var startPos = this.pos, - val = this.readVarint(); +// 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 = {}; - if (val < POW_2_63) return val; +function noop() {} - var pos = this.pos - 2; - while (this.buf[pos] === 0xff) pos--; - if (pos < startPos) pos = startPos; +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; - val = 0; - for (var i = 0; i < pos - startPos + 1; i++) { - var b = ~this.buf[startPos + i] & 0x7f; - val += i < 4 ? b << i * 7 : b * Math.pow(2, i * 7); - } +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; - return -val - 1; - }, +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; - readSVarint: function() { - var num = this.readVarint(); - return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding - }, +},{}],198:[function(require,module,exports){ +(function (global){ +/*! https://mths.be/punycode v1.4.1 by @mathias */ +;(function(root) { + + /** Detect free variables */ + var freeExports = typeof exports == 'object' && exports && + !exports.nodeType && exports; + var freeModule = typeof module == 'object' && module && + !module.nodeType && module; + var freeGlobal = typeof global == 'object' && global; + if ( + freeGlobal.global === freeGlobal || + freeGlobal.window === freeGlobal || + freeGlobal.self === freeGlobal + ) { + root = freeGlobal; + } + + /** + * The `punycode` object. + * @name punycode + * @type Object + */ + var punycode, + + /** Highest positive signed 32-bit float value */ + maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1 + + /** Bootstring parameters */ + base = 36, + tMin = 1, + tMax = 26, + skew = 38, + damp = 700, + initialBias = 72, + initialN = 128, // 0x80 + delimiter = '-', // '\x2D' + + /** Regular expressions */ + regexPunycode = /^xn--/, + regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars + regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators + + /** Error messages */ + errors = { + 'overflow': 'Overflow: input needs wider integers to process', + 'not-basic': 'Illegal input >= 0x80 (not a basic code point)', + 'invalid-input': 'Invalid input' + }, + + /** Convenience shortcuts */ + baseMinusTMin = base - tMin, + floor = Math.floor, + stringFromCharCode = String.fromCharCode, + + /** Temporary variable */ + key; + + /*--------------------------------------------------------------------------*/ + + /** + * A generic error utility function. + * @private + * @param {String} type The error type. + * @returns {Error} Throws a `RangeError` with the applicable error message. + */ + function error(type) { + throw new RangeError(errors[type]); + } + + /** + * A generic `Array#map` utility function. + * @private + * @param {Array} array The array to iterate over. + * @param {Function} callback The function that gets called for every array + * item. + * @returns {Array} A new array of values returned by the callback function. + */ + function map(array, fn) { + var length = array.length; + var result = []; + while (length--) { + result[length] = fn(array[length]); + } + return result; + } + + /** + * A simple `Array#map`-like wrapper to work with domain name strings or email + * addresses. + * @private + * @param {String} domain The domain name or email address. + * @param {Function} callback The function that gets called for every + * character. + * @returns {Array} A new string of characters returned by the callback + * function. + */ + function mapDomain(string, fn) { + var parts = string.split('@'); + var result = ''; + if (parts.length > 1) { + // In email addresses, only the domain name should be punycoded. Leave + // the local part (i.e. everything up to `@`) intact. + result = parts[0] + '@'; + string = parts[1]; + } + // Avoid `split(regex)` for IE8 compatibility. See #17. + string = string.replace(regexSeparators, '\x2E'); + var labels = string.split('.'); + var encoded = map(labels, fn).join('.'); + return result + encoded; + } + + /** + * Creates an array containing the numeric code points of each Unicode + * character in the string. While JavaScript uses UCS-2 internally, + * this function will convert a pair of surrogate halves (each of which + * UCS-2 exposes as separate characters) into a single code point, + * matching UTF-16. + * @see `punycode.ucs2.encode` + * @see + * @memberOf punycode.ucs2 + * @name decode + * @param {String} string The Unicode input string (UCS-2). + * @returns {Array} The new array of code points. + */ + function ucs2decode(string) { + var output = [], + counter = 0, + length = string.length, + value, + extra; + while (counter < length) { + value = string.charCodeAt(counter++); + if (value >= 0xD800 && value <= 0xDBFF && counter < length) { + // high surrogate, and there is a next character + extra = string.charCodeAt(counter++); + if ((extra & 0xFC00) == 0xDC00) { // low surrogate + output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); + } else { + // unmatched surrogate; only append this code unit, in case the next + // code unit is the high surrogate of a surrogate pair + output.push(value); + counter--; + } + } else { + output.push(value); + } + } + return output; + } + + /** + * Creates a string based on an array of numeric code points. + * @see `punycode.ucs2.decode` + * @memberOf punycode.ucs2 + * @name encode + * @param {Array} codePoints The array of numeric code points. + * @returns {String} The new Unicode string (UCS-2). + */ + function ucs2encode(array) { + return map(array, function(value) { + var output = ''; + if (value > 0xFFFF) { + value -= 0x10000; + output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); + value = 0xDC00 | value & 0x3FF; + } + output += stringFromCharCode(value); + return output; + }).join(''); + } + + /** + * Converts a basic code point into a digit/integer. + * @see `digitToBasic()` + * @private + * @param {Number} codePoint The basic numeric code point value. + * @returns {Number} The numeric value of a basic code point (for use in + * representing integers) in the range `0` to `base - 1`, or `base` if + * the code point does not represent a value. + */ + function basicToDigit(codePoint) { + if (codePoint - 48 < 10) { + return codePoint - 22; + } + if (codePoint - 65 < 26) { + return codePoint - 65; + } + if (codePoint - 97 < 26) { + return codePoint - 97; + } + return base; + } + + /** + * Converts a digit/integer into a basic code point. + * @see `basicToDigit()` + * @private + * @param {Number} digit The numeric value of a basic code point. + * @returns {Number} The basic code point whose value (when used for + * representing integers) is `digit`, which needs to be in the range + * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is + * used; else, the lowercase form is used. The behavior is undefined + * if `flag` is non-zero and `digit` has no uppercase form. + */ + function digitToBasic(digit, flag) { + // 0..25 map to ASCII a..z or A..Z + // 26..35 map to ASCII 0..9 + return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); + } + + /** + * Bias adaptation function as per section 3.4 of RFC 3492. + * https://tools.ietf.org/html/rfc3492#section-3.4 + * @private + */ + function adapt(delta, numPoints, firstTime) { + var k = 0; + delta = firstTime ? floor(delta / damp) : delta >> 1; + delta += floor(delta / numPoints); + for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) { + delta = floor(delta / baseMinusTMin); + } + return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); + } + + /** + * Converts a Punycode string of ASCII-only symbols to a string of Unicode + * symbols. + * @memberOf punycode + * @param {String} input The Punycode string of ASCII-only symbols. + * @returns {String} The resulting string of Unicode symbols. + */ + function decode(input) { + // Don't use UCS-2 + var output = [], + inputLength = input.length, + out, + i = 0, + n = initialN, + bias = initialBias, + basic, + j, + index, + oldi, + w, + k, + digit, + t, + /** Cached calculation results */ + baseMinusT; + + // Handle the basic code points: let `basic` be the number of input code + // points before the last delimiter, or `0` if there is none, then copy + // the first basic code points to the output. + + basic = input.lastIndexOf(delimiter); + if (basic < 0) { + basic = 0; + } + + for (j = 0; j < basic; ++j) { + // if it's not a basic code point + if (input.charCodeAt(j) >= 0x80) { + error('not-basic'); + } + output.push(input.charCodeAt(j)); + } + + // Main decoding loop: start just after the last delimiter if any basic code + // points were copied; start at the beginning otherwise. + + for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) { + + // `index` is the index of the next character to be consumed. + // Decode a generalized variable-length integer into `delta`, + // which gets added to `i`. The overflow checking is easier + // if we increase `i` as we go, then subtract off its starting + // value at the end to obtain `delta`. + for (oldi = i, w = 1, k = base; /* no condition */; k += base) { + + if (index >= inputLength) { + error('invalid-input'); + } + + digit = basicToDigit(input.charCodeAt(index++)); + + if (digit >= base || digit > floor((maxInt - i) / w)) { + error('overflow'); + } + + i += digit * w; + t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); + + if (digit < t) { + break; + } + + baseMinusT = base - t; + if (w > floor(maxInt / baseMinusT)) { + error('overflow'); + } + + w *= baseMinusT; + + } + + out = output.length + 1; + bias = adapt(i - oldi, out, oldi == 0); + + // `i` was supposed to wrap around from `out` to `0`, + // incrementing `n` each time, so we'll fix that now: + if (floor(i / out) > maxInt - n) { + error('overflow'); + } + + n += floor(i / out); + i %= out; + + // Insert `n` at position `i` of the output + output.splice(i++, 0, n); + + } + + return ucs2encode(output); + } + + /** + * Converts a string of Unicode symbols (e.g. a domain name label) to a + * Punycode string of ASCII-only symbols. + * @memberOf punycode + * @param {String} input The string of Unicode symbols. + * @returns {String} The resulting Punycode string of ASCII-only symbols. + */ + function encode(input) { + var n, + delta, + handledCPCount, + basicLength, + bias, + j, + m, + q, + k, + t, + currentValue, + output = [], + /** `inputLength` will hold the number of code points in `input`. */ + inputLength, + /** Cached calculation results */ + handledCPCountPlusOne, + baseMinusT, + qMinusT; + + // Convert the input in UCS-2 to Unicode + input = ucs2decode(input); + + // Cache the length + inputLength = input.length; + + // Initialize the state + n = initialN; + delta = 0; + bias = initialBias; + + // Handle the basic code points + for (j = 0; j < inputLength; ++j) { + currentValue = input[j]; + if (currentValue < 0x80) { + output.push(stringFromCharCode(currentValue)); + } + } + + handledCPCount = basicLength = output.length; + + // `handledCPCount` is the number of code points that have been handled; + // `basicLength` is the number of basic code points. + + // Finish the basic string - if it is not empty - with a delimiter + if (basicLength) { + output.push(delimiter); + } + + // Main encoding loop: + while (handledCPCount < inputLength) { + + // All non-basic code points < n have been handled already. Find the next + // larger one: + for (m = maxInt, j = 0; j < inputLength; ++j) { + currentValue = input[j]; + if (currentValue >= n && currentValue < m) { + m = currentValue; + } + } + + // Increase `delta` enough to advance the decoder's state to , + // but guard against overflow + handledCPCountPlusOne = handledCPCount + 1; + if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { + error('overflow'); + } + + delta += (m - n) * handledCPCountPlusOne; + n = m; + + for (j = 0; j < inputLength; ++j) { + currentValue = input[j]; + + if (currentValue < n && ++delta > maxInt) { + error('overflow'); + } + + if (currentValue == n) { + // Represent delta as a generalized variable-length integer + for (q = delta, k = base; /* no condition */; k += base) { + t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); + if (q < t) { + break; + } + qMinusT = q - t; + baseMinusT = base - t; + output.push( + stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)) + ); + q = floor(qMinusT / baseMinusT); + } + + output.push(stringFromCharCode(digitToBasic(q, 0))); + bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); + delta = 0; + ++handledCPCount; + } + } + + ++delta; + ++n; + + } + return output.join(''); + } + + /** + * Converts a Punycode string representing a domain name or an email address + * to Unicode. Only the Punycoded parts of the input will be converted, i.e. + * it doesn't matter if you call it on a string that has already been + * converted to Unicode. + * @memberOf punycode + * @param {String} input The Punycoded domain name or email address to + * convert to Unicode. + * @returns {String} The Unicode representation of the given Punycode + * string. + */ + function toUnicode(input) { + return mapDomain(input, function(string) { + return regexPunycode.test(string) + ? decode(string.slice(4).toLowerCase()) + : string; + }); + } + + /** + * Converts a Unicode string representing a domain name or an email address to + * Punycode. Only the non-ASCII parts of the domain name will be converted, + * i.e. it doesn't matter if you call it with a domain that's already in + * ASCII. + * @memberOf punycode + * @param {String} input The domain name or email address to convert, as a + * Unicode string. + * @returns {String} The Punycode representation of the given domain name or + * email address. + */ + function toASCII(input) { + return mapDomain(input, function(string) { + return regexNonASCII.test(string) + ? 'xn--' + encode(string) + : string; + }); + } + + /*--------------------------------------------------------------------------*/ + + /** Define the public API */ + punycode = { + /** + * A string representing the current Punycode.js version number. + * @memberOf punycode + * @type String + */ + 'version': '1.4.1', + /** + * An object of methods to convert from JavaScript's internal character + * representation (UCS-2) to Unicode code points, and back. + * @see + * @memberOf punycode + * @type Object + */ + 'ucs2': { + 'decode': ucs2decode, + 'encode': ucs2encode + }, + 'decode': decode, + 'encode': encode, + 'toASCII': toASCII, + 'toUnicode': toUnicode + }; + + /** Expose `punycode` */ + // Some AMD build optimizers, like r.js, check for specific condition patterns + // like the following: + if ( + typeof define == 'function' && + typeof define.amd == 'object' && + define.amd + ) { + define('punycode', function() { + return punycode; + }); + } else if (freeExports && freeModule) { + if (module.exports == freeExports) { + // in Node.js, io.js, or RingoJS v0.8.0+ + freeModule.exports = punycode; + } else { + // in Narwhal or RingoJS v0.7.0- + for (key in punycode) { + punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]); + } + } + } else { + // in Rhino or a web browser + root.punycode = punycode; + } + +}(this)); - readBoolean: function() { - return Boolean(this.readVarint()); - }, +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],199:[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. - readString: function() { - var end = this.readVarint() + this.pos, - str = this.buf.toString('utf8', this.pos, end); - this.pos = end; - return str; - }, +'use strict'; - readBytes: function() { - var end = this.readVarint() + this.pos, - buffer = this.buf.slice(this.pos, end); - this.pos = end; - return buffer; - }, +// If obj.hasOwnProperty has been overridden, then calling +// obj.hasOwnProperty(prop) will break. +// See: https://github.com/joyent/node/issues/1707 +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} - // verbose for performance reasons; doesn't affect gzipped size +module.exports = function(qs, sep, eq, options) { + sep = sep || '&'; + eq = eq || '='; + var obj = {}; - readPackedVarint: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readVarint()); - return arr; - }, - readPackedSVarint: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readSVarint()); - return arr; - }, - readPackedBoolean: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readBoolean()); - return arr; - }, - readPackedFloat: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readFloat()); - return arr; - }, - readPackedDouble: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readDouble()); - return arr; - }, - readPackedFixed32: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readFixed32()); - return arr; - }, - readPackedSFixed32: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readSFixed32()); - return arr; - }, - readPackedFixed64: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readFixed64()); - return arr; - }, - readPackedSFixed64: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readSFixed64()); - return arr; - }, + if (typeof qs !== 'string' || qs.length === 0) { + return obj; + } - skip: function(val) { - var type = val & 0x7; - if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {} - else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos; - else if (type === Pbf.Fixed32) this.pos += 4; - else if (type === Pbf.Fixed64) this.pos += 8; - else throw new Error('Unimplemented type: ' + type); - }, + var regexp = /\+/g; + qs = qs.split(sep); - // === WRITING ================================================================= + var maxKeys = 1000; + if (options && typeof options.maxKeys === 'number') { + maxKeys = options.maxKeys; + } - writeTag: function(tag, type) { - this.writeVarint((tag << 3) | type); - }, + var len = qs.length; + // maxKeys <= 0 means that we should not limit keys count + if (maxKeys > 0 && len > maxKeys) { + len = maxKeys; + } - realloc: function(min) { - var length = this.length || 16; + for (var i = 0; i < len; ++i) { + var x = qs[i].replace(regexp, '%20'), + idx = x.indexOf(eq), + kstr, vstr, k, v; - while (length < this.pos + min) length *= 2; + if (idx >= 0) { + kstr = x.substr(0, idx); + vstr = x.substr(idx + 1); + } else { + kstr = x; + vstr = ''; + } - if (length !== this.length) { - var buf = new Buffer(length); - this.buf.copy(buf); - this.buf = buf; - this.length = length; - } - }, + k = decodeURIComponent(kstr); + v = decodeURIComponent(vstr); - finish: function() { - this.length = this.pos; - this.pos = 0; - return this.buf.slice(0, this.length); - }, + if (!hasOwnProperty(obj, k)) { + obj[k] = v; + } else if (isArray(obj[k])) { + obj[k].push(v); + } else { + obj[k] = [obj[k], v]; + } + } - writeFixed32: function(val) { - this.realloc(4); - this.buf.writeUInt32LE(val, this.pos); - this.pos += 4; - }, + return obj; +}; - writeSFixed32: function(val) { - this.realloc(4); - this.buf.writeInt32LE(val, this.pos); - this.pos += 4; - }, +var isArray = Array.isArray || function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; +}; - writeFixed64: function(val) { - this.realloc(8); - this.buf.writeInt32LE(val & -1, this.pos); - this.buf.writeUInt32LE(Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); - this.pos += 8; - }, +},{}],200:[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. - writeSFixed64: function(val) { - this.realloc(8); - this.buf.writeInt32LE(val & -1, this.pos); - this.buf.writeInt32LE(Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); - this.pos += 8; - }, +'use strict'; - writeVarint: function(val) { - val = +val; +var stringifyPrimitive = function(v) { + switch (typeof v) { + case 'string': + return v; - if (val <= 0x7f) { - this.realloc(1); - this.buf[this.pos++] = val; + case 'boolean': + return v ? 'true' : 'false'; - } else if (val <= 0x3fff) { - this.realloc(2); - this.buf[this.pos++] = ((val >>> 0) & 0x7f) | 0x80; - this.buf[this.pos++] = ((val >>> 7) & 0x7f); + case 'number': + return isFinite(v) ? v : ''; - } else if (val <= 0x1fffff) { - this.realloc(3); - this.buf[this.pos++] = ((val >>> 0) & 0x7f) | 0x80; - this.buf[this.pos++] = ((val >>> 7) & 0x7f) | 0x80; - this.buf[this.pos++] = ((val >>> 14) & 0x7f); + default: + return ''; + } +}; - } else if (val <= 0xfffffff) { - this.realloc(4); - this.buf[this.pos++] = ((val >>> 0) & 0x7f) | 0x80; - this.buf[this.pos++] = ((val >>> 7) & 0x7f) | 0x80; - this.buf[this.pos++] = ((val >>> 14) & 0x7f) | 0x80; - this.buf[this.pos++] = ((val >>> 21) & 0x7f); +module.exports = function(obj, sep, eq, name) { + sep = sep || '&'; + eq = eq || '='; + if (obj === null) { + obj = undefined; + } - } else { - var pos = this.pos; - while (val >= 0x80) { - this.realloc(1); - this.buf[this.pos++] = (val & 0xff) | 0x80; - val /= 0x80; - } - this.realloc(1); - this.buf[this.pos++] = val | 0; - if (this.pos - pos > 10) throw new Error('Given varint doesn\'t fit into 10 bytes'); - } - }, + if (typeof obj === 'object') { + return map(objectKeys(obj), function(k) { + var ks = encodeURIComponent(stringifyPrimitive(k)) + eq; + if (isArray(obj[k])) { + return map(obj[k], function(v) { + return ks + encodeURIComponent(stringifyPrimitive(v)); + }).join(sep); + } else { + return ks + encodeURIComponent(stringifyPrimitive(obj[k])); + } + }).join(sep); - writeSVarint: function(val) { - this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2); - }, + } - writeBoolean: function(val) { - this.writeVarint(Boolean(val)); - }, + if (!name) return ''; + return encodeURIComponent(stringifyPrimitive(name)) + eq + + encodeURIComponent(stringifyPrimitive(obj)); +}; - writeString: function(str) { - str = String(str); - var bytes = Buffer.byteLength(str); - this.writeVarint(bytes); - this.realloc(bytes); - this.buf.write(str, this.pos); - this.pos += bytes; - }, +var isArray = Array.isArray || function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; +}; - writeFloat: function(val) { - this.realloc(4); - this.buf.writeFloatLE(val, this.pos); - this.pos += 4; - }, +function map (xs, f) { + if (xs.map) return xs.map(f); + var res = []; + for (var i = 0; i < xs.length; i++) { + res.push(f(xs[i], i)); + } + return res; +} - writeDouble: function(val) { - this.realloc(8); - this.buf.writeDoubleLE(val, this.pos); - this.pos += 8; - }, +var objectKeys = Object.keys || function (obj) { + var res = []; + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key); + } + return res; +}; - writeBytes: function(buffer) { - var len = buffer.length; - this.writeVarint(len); - this.realloc(len); - for (var i = 0; i < len; i++) this.buf[this.pos++] = buffer[i]; - }, +},{}],201:[function(require,module,exports){ +'use strict'; - writeRawMessage: function(fn, obj) { - this.pos++; // reserve 1 byte for short message length +exports.decode = exports.parse = require('./decode'); +exports.encode = exports.stringify = require('./encode'); - // write the message directly to the buffer and see how much was written - var startPos = this.pos; - fn(obj, this); - var len = this.pos - startPos; +},{"./decode":199,"./encode":200}],202:[function(require,module,exports){ +'use strict'; + +module.exports = partialSort; + +// Floyd-Rivest selection algorithm: +// Rearrange items so that all items in the [left, k] range are smaller than all items in (k, right]; +// The k-th element will have the (k - left + 1)th smallest value in [left, right] - var varintLen = - len <= 0x7f ? 1 : - len <= 0x3fff ? 2 : - len <= 0x1fffff ? 3 : - len <= 0xfffffff ? 4 : Math.ceil(Math.log(len) / (Math.LN2 * 7)); +function partialSort(arr, k, left, right, compare) { + left = left || 0; + right = right || (arr.length - 1); + compare = compare || defaultCompare; - // if 1 byte isn't enough for encoding message length, shift the data to the right - if (varintLen > 1) { - this.realloc(varintLen - 1); - for (var i = this.pos - 1; i >= startPos; i--) this.buf[i + varintLen - 1] = this.buf[i]; + 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)); + partialSort(arr, k, newLeft, newRight, compare); } - // finally, write the message length in the reserved place and restore the position - this.pos = startPos - 1; - this.writeVarint(len); - this.pos += len; - }, + var t = arr[k]; + var i = left; + var j = right; - writeMessage: function(tag, fn, obj) { - this.writeTag(tag, Pbf.Bytes); - this.writeRawMessage(fn, obj); - }, + swap(arr, left, k); + if (compare(arr[right], t) > 0) swap(arr, left, right); - writePackedVarint: function(tag, arr) { this.writeMessage(tag, writePackedVarint, arr); }, - writePackedSVarint: function(tag, arr) { this.writeMessage(tag, writePackedSVarint, arr); }, - writePackedBoolean: function(tag, arr) { this.writeMessage(tag, writePackedBoolean, arr); }, - writePackedFloat: function(tag, arr) { this.writeMessage(tag, writePackedFloat, arr); }, - writePackedDouble: function(tag, arr) { this.writeMessage(tag, writePackedDouble, arr); }, - writePackedFixed32: function(tag, arr) { this.writeMessage(tag, writePackedFixed32, arr); }, - writePackedSFixed32: function(tag, arr) { this.writeMessage(tag, writePackedSFixed32, arr); }, - writePackedFixed64: function(tag, arr) { this.writeMessage(tag, writePackedFixed64, arr); }, - writePackedSFixed64: function(tag, arr) { this.writeMessage(tag, writePackedSFixed64, arr); }, + while (i < j) { + swap(arr, i, j); + i++; + j--; + while (compare(arr[i], t) < 0) i++; + while (compare(arr[j], t) > 0) j--; + } - writeBytesField: function(tag, buffer) { - this.writeTag(tag, Pbf.Bytes); - this.writeBytes(buffer); - }, - writeFixed32Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed32); - this.writeFixed32(val); - }, - writeSFixed32Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed32); - this.writeSFixed32(val); - }, - writeFixed64Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed64); - this.writeFixed64(val); - }, - writeSFixed64Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed64); - this.writeSFixed64(val); - }, - writeVarintField: function(tag, val) { - this.writeTag(tag, Pbf.Varint); - this.writeVarint(val); - }, - writeSVarintField: function(tag, val) { - this.writeTag(tag, Pbf.Varint); - this.writeSVarint(val); - }, - writeStringField: function(tag, str) { - this.writeTag(tag, Pbf.Bytes); - this.writeString(str); - }, - writeFloatField: function(tag, val) { - this.writeTag(tag, Pbf.Fixed32); - this.writeFloat(val); - }, - writeDoubleField: function(tag, val) { - this.writeTag(tag, Pbf.Fixed64); - this.writeDouble(val); - }, - writeBooleanField: function(tag, val) { - this.writeVarintField(tag, Boolean(val)); + 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 writePackedVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]); } -function writePackedSVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]); } -function writePackedFloat(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]); } -function writePackedDouble(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]); } -function writePackedBoolean(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]); } -function writePackedFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]); } -function writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); } -function writePackedFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]); } -function writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); } +function swap(arr, i, j) { + var tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; +} -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./buffer":159}],161:[function(require,module,exports){ -arguments[4][5][0].apply(exports,arguments) -},{"dup":5}],162:[function(require,module,exports){ -'use strict'; +function defaultCompare(a, b) { + return a < b ? -1 : a > b ? 1 : 0; +} -module.exports = Point; +},{}],203:[function(require,module,exports){ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.ShelfPack = factory()); +}(this, function () { -function Point(x, y) { - this.x = x; - this.y = y; +/** + * Create a new ShelfPack bin allocator. + * + * Uses the Shelf Best Height Fit algorithm from + * http://clb.demon.fi/files/RectangleBinPack.pdf + * + * @class ShelfPack + * @param {number} [w=64] Initial width of the sprite + * @param {number} [h=64] Initial width of the sprite + * @param {Object} [options] + * @param {boolean} [options.autoResize=false] If `true`, the sprite will automatically grow + * @example + * var sprite = new ShelfPack(64, 64, { autoResize: false }); + */ +function ShelfPack(w, h, options) { + options = options || {}; + this.w = w || 64; + this.h = h || 64; + this.autoResize = !!options.autoResize; + this.shelves = []; + this.stats = {}; + this.count = function(h) { + this.stats[h] = (this.stats[h] | 0) + 1; + }; } -Point.prototype = { - clone: function() { return new Point(this.x, this.y); }, +/** + * Batch pack multiple bins into the sprite. + * + * @param {Array} bins Array of requested bins - each object should have `width`, `height` (or `w`, `h`) properties + * @param {Object} [options] + * @param {boolean} [options.inPlace=false] If `true`, the supplied bin objects will be updated inplace with `x` and `y` properties + * @returns {Array} Array of allocated bins - each bin is an object with `x`, `y`, `w`, `h` properties + * @example + * var bins = [ + * { id: 'a', width: 12, height: 12 }, + * { id: 'b', width: 12, height: 16 }, + * { id: 'c', width: 12, height: 24 } + * ]; + * var results = sprite.pack(bins, { inPlace: false }); + */ +ShelfPack.prototype.pack = function(bins, options) { + bins = [].concat(bins); + options = options || {}; - add: function(p) { return this.clone()._add(p); }, - sub: function(p) { return this.clone()._sub(p); }, - mult: function(k) { return this.clone()._mult(k); }, - div: function(k) { return this.clone()._div(k); }, - rotate: function(a) { return this.clone()._rotate(a); }, - matMult: function(m) { return this.clone()._matMult(m); }, - unit: function() { return this.clone()._unit(); }, - perp: function() { return this.clone()._perp(); }, - round: function() { return this.clone()._round(); }, + var results = [], + w, h, allocation; - mag: function() { - return Math.sqrt(this.x * this.x + this.y * this.y); - }, + for (var i = 0; i < bins.length; i++) { + w = bins[i].w || bins[i].width; + h = bins[i].h || bins[i].height; + if (w && h) { + allocation = this.packOne(w, h); + if (!allocation) { + continue; + } + if (options.inPlace) { + bins[i].x = allocation.x; + bins[i].y = allocation.y; + } + results.push(allocation); + } + } - equals: function(p) { - return this.x === p.x && - this.y === p.y; - }, + // Shrink the width/height of the sprite to the bare minimum. + // Since shelf-pack doubles first width, then height when running out of shelf space + // this can result in fairly large unused space both in width and height if that happens + // towards the end of bin packing. + if (this.shelves.length > 0) { + var w2 = 0; + var h2 = 0; - dist: function(p) { - return Math.sqrt(this.distSqr(p)); - }, + for (var j = 0; j < this.shelves.length; j++) { + var shelf = this.shelves[j]; + h2 += shelf.h; + w2 = Math.max(shelf.w - shelf.free, w2); + } - distSqr: function(p) { - var dx = p.x - this.x, - dy = p.y - this.y; - return dx * dx + dy * dy; - }, + this.resize(w2, h2); + } - angle: function() { - return Math.atan2(this.y, this.x); - }, + return results; +}; + +/** + * Pack a single bin into the sprite. + * + * @param {number} w Width of the bin to allocate + * @param {number} h Height of the bin to allocate + * @returns {Object} Allocated bin object with `x`, `y`, `w`, `h` properties, or `null` if allocation failed + * @example + * var results = sprite.packOne(12, 16); + */ +ShelfPack.prototype.packOne = function(w, h) { + var y = 0, + best = { shelf: -1, waste: Infinity }, + shelf, waste; + + // find the best shelf + for (var i = 0; i < this.shelves.length; i++) { + shelf = this.shelves[i]; + y += shelf.h; + + // exactly the right height with width to spare, pack it.. + if (h === shelf.h && w <= shelf.free) { + this.count(h); + return shelf.alloc(w, h); + } + // not enough height or width, skip it.. + if (h > shelf.h || w > shelf.free) { + continue; + } + // maybe enough height or width, minimize waste.. + if (h < shelf.h && w <= shelf.free) { + waste = shelf.h - h; + if (waste < best.waste) { + best.waste = waste; + best.shelf = i; + } + } + } + + if (best.shelf !== -1) { + shelf = this.shelves[best.shelf]; + this.count(h); + return shelf.alloc(w, h); + } - angleTo: function(b) { - return Math.atan2(this.y - b.y, this.x - b.x); - }, + // add shelf.. + if (h <= (this.h - y) && w <= this.w) { + shelf = new Shelf(y, this.w, h); + this.shelves.push(shelf); + this.count(h); + return shelf.alloc(w, h); + } - angleWith: function(b) { - return this.angleWithSep(b.x, b.y); - }, + // no more space.. + // If `autoResize` option is set, grow the sprite as follows: + // * double whichever sprite dimension is smaller (`w1` or `h1`) + // * if sprite dimensions are equal, grow width before height + // * accomodate very large bin requests (big `w` or `h`) + if (this.autoResize) { + var h1, h2, w1, w2; - // Find the angle of the two vectors, solving the formula for the cross product a x b = |a||b|sin(θ) for θ. - angleWithSep: function(x, y) { - return Math.atan2( - this.x * y - this.y * x, - this.x * x + this.y * y); - }, + h1 = h2 = this.h; + w1 = w2 = this.w; - _matMult: function(m) { - var x = m[0] * this.x + m[1] * this.y, - y = m[2] * this.x + m[3] * this.y; - this.x = x; - this.y = y; - return this; - }, + if (w1 <= h1 || w > w1) { // grow width.. + w2 = Math.max(w, w1) * 2; + } + if (h1 < w1 || h > h1) { // grow height.. + h2 = Math.max(h, h1) * 2; + } - _add: function(p) { - this.x += p.x; - this.y += p.y; - return this; - }, + this.resize(w2, h2); + return this.packOne(w, h); // retry + } - _sub: function(p) { - this.x -= p.x; - this.y -= p.y; - return this; - }, + return null; +}; - _mult: function(k) { - this.x *= k; - this.y *= k; - return this; - }, +/** + * Clear the sprite. + * + * @example + * sprite.clear(); + */ +ShelfPack.prototype.clear = function() { + this.shelves = []; + this.stats = {}; +}; - _div: function(k) { - this.x /= k; - this.y /= k; - return this; - }, +/** + * Resize the sprite. + * + * @param {number} w Requested new sprite width + * @param {number} h Requested new sprite height + * @returns {boolean} `true` if resize succeeded, `false` if failed + * @example + * sprite.resize(256, 256); + */ +ShelfPack.prototype.resize = function(w, h) { + this.w = w; + this.h = h; + for (var i = 0; i < this.shelves.length; i++) { + this.shelves[i].resize(w); + } + return true; +}; - _unit: function() { - this._div(this.mag()); - return this; - }, - _perp: function() { - var y = this.y; - this.y = this.x; - this.x = -y; - return this; - }, - _rotate: function(angle) { - var cos = Math.cos(angle), - sin = Math.sin(angle), - x = cos * this.x - sin * this.y, - y = sin * this.x + cos * this.y; - this.x = x; - this.y = y; - return this; - }, +/** + * Create a new Shelf. + * + * @private + * @class Shelf + * @param {number} y Top coordinate of the new shelf + * @param {number} w Width of the new shelf + * @param {number} h Height of the new shelf + * @example + * var shelf = new Shelf(64, 512, 24); + */ +function Shelf(y, w, h) { + this.x = 0; + this.y = y; + this.w = this.free = w; + this.h = h; +} - _round: function() { - this.x = Math.round(this.x); - this.y = Math.round(this.y); - return this; +/** + * Allocate a single bin into the shelf. + * + * @private + * @param {number} w Width of the bin to allocate + * @param {number} h Height of the bin to allocate + * @returns {Object} Allocated bin object with `x`, `y`, `w`, `h` properties, or `null` if allocation failed + * @example + * shelf.alloc(12, 16); + */ +Shelf.prototype.alloc = function(w, h) { + if (w > this.free || h > this.h) { + return null; } + var x = this.x; + this.x += w; + this.free -= w; + return { x: x, y: this.y, w: w, h: h, width: w, height: h }; }; -// constructs Point from an array if necessary -Point.convert = function (a) { - if (a instanceof Point) { - return a; - } - if (Array.isArray(a)) { - return new Point(a[0], a[1]); - } - return a; +/** + * Resize the shelf. + * + * @private + * @param {number} w Requested new width of the shelf + * @returns {boolean} true if resize succeeded, false if failed + * @example + * shelf.resize(512); + */ +Shelf.prototype.resize = function(w) { + this.free += (w - this.w); + this.w = w; + return true; }; -},{}],163:[function(require,module,exports){ -/* - (c) 2015, Vladimir Agafonkin - RBush, a JavaScript library for high-performance 2D spatial indexing of points and rectangles. - https://github.com/mourner/rbush -*/ +return ShelfPack; -(function () { +})); +},{}],204:[function(require,module,exports){ 'use strict'; -function rbush(maxEntries, format) { - - // jshint newcap: false, validthis: true - if (!(this instanceof rbush)) return new rbush(maxEntries, format); +var kdbush = require('kdbush'); - // 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); - } +module.exports = supercluster; - this.clear(); +function supercluster(options) { + return new SuperCluster(options); } -rbush.prototype = { +function SuperCluster(options) { + this.options = extend(Object.create(this.options), options); + this.trees = new Array(this.options.maxZoom + 1); +} - all: function () { - return this._all(this.data, []); +SuperCluster.prototype = { + options: { + minZoom: 0, // min zoom to generate clusters on + maxZoom: 16, // max zoom level to cluster the points on + radius: 40, // cluster radius in pixels + extent: 512, // tile extent (radius is calculated relative to it) + nodeSize: 64, // size of the KD-tree leaf node, affects performance + log: false // whether to log timing info }, - search: function (bbox) { + load: function (points) { + var log = this.options.log; + + if (log) console.time('total time'); + + var timerId = 'prepare ' + points.length + ' points'; + if (log) console.time(timerId); - var node = this.data, - result = [], - toBBox = this.toBBox; + this.points = points; - if (!intersects(bbox, node.bbox)) return result; + // generate a cluster object for each point + var clusters = points.map(createPointCluster); + if (log) console.timeEnd(timerId); - var nodesToSearch = [], - i, len, child, childBBox; + // cluster points on max zoom, then cluster the results on previous zoom, etc.; + // results in a cluster hierarchy across zoom levels + for (var z = this.options.maxZoom; z >= this.options.minZoom; z--) { + var now = +Date.now(); - while (node) { - for (i = 0, len = node.children.length; i < len; i++) { + // index input points into a KD-tree + this.trees[z + 1] = kdbush(clusters, getX, getY, this.options.nodeSize, Float32Array); - child = node.children[i]; - childBBox = node.leaf ? toBBox(child) : child.bbox; + clusters = this._cluster(clusters, z); // create a new set of clusters for the zoom - 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(); + if (log) console.log('z%d: %d clusters in %dms', z, clusters.length, +Date.now() - now); } - return result; + // index top-level clusters + this.trees[this.options.minZoom] = kdbush(clusters, getX, getY, this.options.nodeSize, Float32Array); + + if (log) console.timeEnd('total time'); + + return this; }, - collides: function (bbox) { + getClusters: function (bbox, zoom) { + var tree = this.trees[this._limitZoom(zoom)]; + var ids = tree.range(lngX(bbox[0]), latY(bbox[3]), lngX(bbox[2]), latY(bbox[1])); + var clusters = []; + for (var i = 0; i < ids.length; i++) { + var c = tree.points[ids[i]]; + clusters.push(c.id !== -1 ? this.points[c.id] : getClusterJSON(c)); + } + return clusters; + }, - var node = this.data, - toBBox = this.toBBox; + getTile: function (z, x, y) { + var tree = this.trees[this._limitZoom(z)]; + var z2 = Math.pow(2, z); + var extent = this.options.extent; + var r = this.options.radius; + var p = r / extent; + var top = (y - p) / z2; + var bottom = (y + 1 + p) / z2; - if (!intersects(bbox, node.bbox)) return false; + var tile = { + features: [] + }; - var nodesToSearch = [], - i, len, child, childBBox; + this._addTileFeatures( + tree.range((x - p) / z2, top, (x + 1 + p) / z2, bottom), + tree.points, x, y, z2, tile); - while (node) { - for (i = 0, len = node.children.length; i < len; i++) { + if (x === 0) { + this._addTileFeatures( + tree.range(1 - p / z2, top, 1, bottom), + tree.points, z2, y, z2, tile); + } + if (x === z2 - 1) { + this._addTileFeatures( + tree.range(0, top, p / z2, bottom), + tree.points, -1, y, z2, tile); + } - child = node.children[i]; - childBBox = node.leaf ? toBBox(child) : child.bbox; + return tile.features.length ? tile : null; + }, - if (intersects(bbox, childBBox)) { - if (node.leaf || contains(bbox, childBBox)) return true; - nodesToSearch.push(child); - } - } - node = nodesToSearch.pop(); + _addTileFeatures: function (ids, points, x, y, z2, tile) { + for (var i = 0; i < ids.length; i++) { + var c = points[ids[i]]; + tile.features.push({ + type: 1, + geometry: [[ + Math.round(this.options.extent * (c.x * z2 - x)), + Math.round(this.options.extent * (c.y * z2 - y)) + ]], + tags: c.id !== -1 ? this.points[c.id].properties : getClusterProperties(c) + }); } + }, - return false; + _limitZoom: function (z) { + return Math.max(this.options.minZoom, Math.min(z, this.options.maxZoom + 1)); }, - load: function (data) { - if (!(data && data.length)) return this; + _cluster: function (points, zoom) { + var clusters = []; + var r = this.options.radius / (this.options.extent * Math.pow(2, zoom)); + + // loop through each point + for (var i = 0; i < points.length; i++) { + var p = points[i]; + // if we've already visited the point at this zoom level, skip it + if (p.zoom <= zoom) continue; + p.zoom = zoom; + + // find all nearby points + var tree = this.trees[zoom + 1]; + var neighborIds = tree.within(p.x, p.y, r); + + var foundNeighbors = false; + var numPoints = p.numPoints; + var wx = p.x * numPoints; + var wy = p.y * numPoints; - if (data.length < this._minEntries) { - for (var i = 0, len = data.length; i < len; i++) { - this.insert(data[i]); + for (var j = 0; j < neighborIds.length; j++) { + var b = tree.points[neighborIds[j]]; + // filter out neighbors that are too far or already processed + if (zoom < b.zoom) { + foundNeighbors = true; + b.zoom = zoom; // save the zoom (so it doesn't get processed twice) + wx += b.x * b.numPoints; // accumulate coordinates for calculating weighted center + wy += b.y * b.numPoints; + numPoints += b.numPoints; + } } - return this; - } - // recursively build the tree with the given data from stratch using OMT algorithm - var node = this._build(data.slice(), 0, data.length - 1, 0); + clusters.push(foundNeighbors ? createCluster(wx / numPoints, wy / numPoints, numPoints, -1) : p); + } - if (!this.data.children.length) { - // save as is if tree is empty - this.data = node; + return clusters; + } +}; - } else if (this.data.height === node.height) { - // split root if trees have the same height - this._splitRoot(this.data, node); +function createCluster(x, y, numPoints, id) { + return { + x: x, // weighted cluster center + y: y, + zoom: Infinity, // the last zoom the cluster was processed at + id: id, // index of the source feature in the original input array + numPoints: numPoints + }; +} - } else { - if (this.data.height < node.height) { - // swap trees if inserted one is bigger - var tmpNode = this.data; - this.data = node; - node = tmpNode; - } +function createPointCluster(p, i) { + var coords = p.geometry.coordinates; + return createCluster(lngX(coords[0]), latY(coords[1]), 1, i); +} - // insert the small tree into the large tree at appropriate level - this._insert(node, this.data.height - node.height - 1, true); +function getClusterJSON(cluster) { + return { + type: 'Feature', + properties: getClusterProperties(cluster), + geometry: { + type: 'Point', + coordinates: [xLng(cluster.x), yLat(cluster.y)] } + }; +} - return this; - }, +function getClusterProperties(cluster) { + var count = cluster.numPoints; + var abbrev = count >= 10000 ? Math.round(count / 1000) + 'k' : + count >= 1000 ? (Math.round(count / 100) / 10) + 'k' : count; + return { + cluster: true, + point_count: count, + point_count_abbreviated: abbrev + }; +} - insert: function (item) { - if (item) this._insert(item, this.data.height - 1); - return this; - }, +// longitude/latitude to spherical mercator in [0..1] range +function lngX(lng) { + return lng / 360 + 0.5; +} +function latY(lat) { + var sin = Math.sin(lat * Math.PI / 180), + y = (0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI); + return y < 0 ? 0 : + y > 1 ? 1 : y; +} - clear: function () { - this.data = { - children: [], - height: 1, - bbox: empty(), - leaf: true - }; - return this; - }, +// spherical mercator to longitude/latitude +function xLng(x) { + return (x - 0.5) * 360; +} +function yLat(y) { + var y2 = (180 - y * 360) * Math.PI / 180; + return 360 * Math.atan(Math.exp(y2)) / Math.PI - 90; +} - remove: function (item) { - if (!item) return this; +function extend(dest, src) { + for (var id in src) dest[id] = src[id]; + return dest; +} - var node = this.data, - bbox = this.toBBox(item), - path = [], - indexes = [], - i, parent, index, goingUp; +function getX(p) { + return p.x; +} +function getY(p) { + return p.y; +} - // depth-first iterative tree traversal - while (node || path.length) { +},{"kdbush":41}],205:[function(require,module,exports){ +'use strict'; - if (!node) { // go up - node = path.pop(); - parent = path[path.length - 1]; - i = indexes.pop(); - goingUp = true; - } +module.exports = TinyQueue; - if (node.leaf) { // check current node - index = node.children.indexOf(item); +function TinyQueue(data, compare) { + if (!(this instanceof TinyQueue)) return new TinyQueue(data, compare); - 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; - } - } + this.data = data || []; + this.length = this.data.length; + this.compare = compare || defaultCompare; - if (!goingUp && !node.leaf && contains(node.bbox, bbox)) { // go down - path.push(node); - indexes.push(i); - i = 0; - parent = node; - node = node.children[0]; + if (data) for (var i = Math.floor(this.length / 2); i >= 0; i--) this._down(i); +} - } else if (parent) { // go right - i++; - node = parent.children[i]; - goingUp = false; +function defaultCompare(a, b) { + return a < b ? -1 : a > b ? 1 : 0; +} - } else node = null; // nothing found - } +TinyQueue.prototype = { - return this; + push: function (item) { + this.data.push(item); + this.length++; + this._up(this.length - 1); }, - toBBox: function (item) { return item; }, - - compareMinX: function (a, b) { return a[0] - b[0]; }, - compareMinY: function (a, b) { return a[1] - b[1]; }, - - toJSON: function () { return this.data; }, + pop: function () { + var top = this.data[0]; + this.data[0] = this.data[this.length - 1]; + this.length--; + this.data.pop(); + this._down(0); + return top; + }, - fromJSON: function (data) { - this.data = data; - return this; + peek: function () { + return this.data[0]; }, - _all: function (node, result) { - var nodesToSearch = []; - while (node) { - if (node.leaf) result.push.apply(result, node.children); - else nodesToSearch.push.apply(nodesToSearch, node.children); + _up: function (pos) { + var data = this.data, + compare = this.compare; + + while (pos > 0) { + var parent = Math.floor((pos - 1) / 2); + if (compare(data[pos], data[parent]) < 0) { + swap(data, parent, pos); + pos = parent; - node = nodesToSearch.pop(); + } else break; } - return result; }, - _build: function (items, left, right, height) { + _down: function (pos) { + var data = this.data, + compare = this.compare, + len = this.length; - var N = right - left + 1, - M = this._maxEntries, - node; + while (true) { + var left = 2 * pos + 1, + right = left + 1, + min = pos; - if (N <= M) { - // reached leaf level; return leaf - node = { - children: items.slice(left, right + 1), - height: 1, - bbox: null, - leaf: true - }; - calcBBox(node, this.toBBox); - return node; - } + if (left < len && compare(data[left], data[min]) < 0) min = left; + if (right < len && compare(data[right], data[min]) < 0) min = right; - if (!height) { - // target height of the bulk-loaded tree - height = Math.ceil(Math.log(N) / Math.log(M)); + if (min === pos) return; - // target number of root entries to maximize storage utilization - M = Math.ceil(N / Math.pow(M, height - 1)); + swap(data, min, pos); + pos = min; } + } +}; - node = { - children: [], - height: height, - bbox: null, - leaf: false - }; - - // split the items into M mostly square tiles +function swap(data, i, j) { + var tmp = data[i]; + data[i] = data[j]; + data[j] = tmp; +} - var N2 = Math.ceil(N / M), - N1 = N2 * Math.ceil(Math.sqrt(M)), - i, j, right2, right3; +},{}],206:[function(require,module,exports){ +/* + * Copyright (C) 2008 Apple Inc. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. + * + * Ported from Webkit + * http://svn.webkit.org/repository/webkit/trunk/Source/WebCore/platform/graphics/UnitBezier.h + */ - multiSelect(items, left, right, N1, this.compareMinX); +module.exports = UnitBezier; - for (i = left; i <= right; i += N1) { +function UnitBezier(p1x, p1y, p2x, p2y) { + // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1). + this.cx = 3.0 * p1x; + this.bx = 3.0 * (p2x - p1x) - this.cx; + this.ax = 1.0 - this.cx - this.bx; - right2 = Math.min(i + N1 - 1, right); + this.cy = 3.0 * p1y; + this.by = 3.0 * (p2y - p1y) - this.cy; + this.ay = 1.0 - this.cy - this.by; - multiSelect(items, i, right2, N2, this.compareMinY); + this.p1x = p1x; + this.p1y = p2y; + this.p2x = p2x; + this.p2y = p2y; +} - for (j = i; j <= right2; j += N2) { +UnitBezier.prototype.sampleCurveX = function(t) { + // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule. + return ((this.ax * t + this.bx) * t + this.cx) * t; +}; - right3 = Math.min(j + N2 - 1, right2); +UnitBezier.prototype.sampleCurveY = function(t) { + return ((this.ay * t + this.by) * t + this.cy) * t; +}; - // pack each entry recursively - node.children.push(this._build(items, j, right3, height - 1)); - } - } +UnitBezier.prototype.sampleCurveDerivativeX = function(t) { + return (3.0 * this.ax * t + 2.0 * this.bx) * t + this.cx; +}; - calcBBox(node, this.toBBox); +UnitBezier.prototype.solveCurveX = function(x, epsilon) { + if (typeof epsilon === 'undefined') epsilon = 1e-6; - return node; - }, + var t0, t1, t2, x2, i; - _chooseSubtree: function (bbox, node, level, path) { + // First try a few iterations of Newton's method -- normally very fast. + for (t2 = x, i = 0; i < 8; i++) { - var i, len, child, targetNode, area, enlargement, minArea, minEnlargement; + x2 = this.sampleCurveX(t2) - x; + if (Math.abs(x2) < epsilon) return t2; - while (true) { - path.push(node); + var d2 = this.sampleCurveDerivativeX(t2); + if (Math.abs(d2) < 1e-6) break; - if (node.leaf || path.length - 1 === level) break; + t2 = t2 - x2 / d2; + } - minArea = minEnlargement = Infinity; + // Fall back to the bisection method for reliability. + t0 = 0.0; + t1 = 1.0; + t2 = x; - for (i = 0, len = node.children.length; i < len; i++) { - child = node.children[i]; - area = bboxArea(child.bbox); - enlargement = enlargedArea(bbox, child.bbox) - area; + if (t2 < t0) return t0; + if (t2 > t1) return t1; - // choose entry with the least area enlargement - if (enlargement < minEnlargement) { - minEnlargement = enlargement; - minArea = area < minArea ? area : minArea; - targetNode = child; + while (t0 < t1) { - } else if (enlargement === minEnlargement) { - // otherwise choose one with the smallest area - if (area < minArea) { - minArea = area; - targetNode = child; - } - } - } + x2 = this.sampleCurveX(t2); + if (Math.abs(x2 - x) < epsilon) return t2; - node = targetNode; + if (x > x2) { + t0 = t2; + } else { + t1 = t2; } - return node; - }, - - _insert: function (item, level, isNode) { - - var toBBox = this.toBBox, - bbox = isNode ? item.bbox : 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, bbox); + t2 = (t1 - t0) * 0.5 + t0; + } - // 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; - } + // Failure. + return t2; +}; - // adjust bboxes along the insertion path - this._adjustParentBBoxes(bbox, insertPath, level); - }, +UnitBezier.prototype.solve = function(x, epsilon) { + return this.sampleCurveY(this.solveCurveX(x, epsilon)); +}; - // split overflowed node into two - _split: function (insertPath, level) { +},{}],207:[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. - var node = insertPath[level], - M = node.children.length, - m = this._minEntries; +'use strict'; - this._chooseSplitAxis(node, m, M); +var punycode = require('punycode'); +var util = require('./util'); - var splitIndex = this._chooseSplitIndex(node, m, M); +exports.parse = urlParse; +exports.resolve = urlResolve; +exports.resolveObject = urlResolveObject; +exports.format = urlFormat; + +exports.Url = Url; + +function Url() { + this.protocol = null; + this.slashes = null; + this.auth = null; + this.host = null; + this.port = null; + this.hostname = null; + this.hash = null; + this.search = null; + this.query = null; + this.pathname = null; + this.path = null; + this.href = null; +} + +// Reference: RFC 3986, RFC 1808, RFC 2396 + +// define these here so at least they only have to be +// compiled once on the first module load. +var protocolPattern = /^([a-z0-9.+-]+:)/i, + portPattern = /:[0-9]*$/, + + // Special case for a simple path URL + simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/, + + // RFC 2396: characters reserved for delimiting URLs. + // We actually just auto-escape these. + delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'], + + // RFC 2396: characters not allowed for various reasons. + unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims), + + // Allowed by RFCs, but cause of XSS attacks. Always escape these. + autoEscape = ['\''].concat(unwise), + // Characters that are never ever allowed in a hostname. + // Note that any invalid chars are also handled, but these + // are the ones that are *expected* to be seen, so we fast-path + // them. + nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape), + hostEndingChars = ['/', '?', '#'], + hostnameMaxLen = 255, + hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/, + hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/, + // protocols that can allow "unsafe" and "unwise" chars. + unsafeProtocol = { + 'javascript': true, + 'javascript:': true + }, + // protocols that never have a hostname. + hostlessProtocol = { + 'javascript': true, + 'javascript:': true + }, + // protocols that always contain a // bit. + slashedProtocol = { + 'http': true, + 'https': true, + 'ftp': true, + 'gopher': true, + 'file': true, + 'http:': true, + 'https:': true, + 'ftp:': true, + 'gopher:': true, + 'file:': true + }, + querystring = require('querystring'); + +function urlParse(url, parseQueryString, slashesDenoteHost) { + if (url && util.isObject(url) && url instanceof Url) return url; + + var u = new Url; + u.parse(url, parseQueryString, slashesDenoteHost); + return u; +} + +Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) { + if (!util.isString(url)) { + throw new TypeError("Parameter 'url' must be a string, not " + typeof url); + } - var newNode = { - children: node.children.splice(splitIndex, node.children.length - splitIndex), - height: node.height, - bbox: null, - leaf: false - }; + // Copy chrome, IE, opera backslash-handling behavior. + // Back slashes before the query string get converted to forward slashes + // See: https://code.google.com/p/chromium/issues/detail?id=25916 + var queryIndex = url.indexOf('?'), + splitter = + (queryIndex !== -1 && queryIndex < url.indexOf('#')) ? '?' : '#', + uSplit = url.split(splitter), + slashRegex = /\\/g; + uSplit[0] = uSplit[0].replace(slashRegex, '/'); + url = uSplit.join(splitter); + + var rest = url; + + // trim before proceeding. + // This is to support parse stuff like " http://foo.com \n" + rest = rest.trim(); + + if (!slashesDenoteHost && url.split('#').length === 1) { + // Try fast path regexp + var simplePath = simplePathPattern.exec(rest); + if (simplePath) { + this.path = rest; + this.href = rest; + this.pathname = simplePath[1]; + if (simplePath[2]) { + this.search = simplePath[2]; + if (parseQueryString) { + this.query = querystring.parse(this.search.substr(1)); + } else { + this.query = this.search.substr(1); + } + } else if (parseQueryString) { + this.search = ''; + this.query = {}; + } + return this; + } + } - if (node.leaf) newNode.leaf = true; + var proto = protocolPattern.exec(rest); + if (proto) { + proto = proto[0]; + var lowerProto = proto.toLowerCase(); + this.protocol = lowerProto; + rest = rest.substr(proto.length); + } - calcBBox(node, this.toBBox); - calcBBox(newNode, this.toBBox); + // figure out if it's got a host + // user@server is *always* interpreted as a hostname, and url + // resolution will treat //foo/bar as host=foo,path=bar because that's + // how the browser resolves relative URLs. + if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) { + var slashes = rest.substr(0, 2) === '//'; + if (slashes && !(proto && hostlessProtocol[proto])) { + rest = rest.substr(2); + this.slashes = true; + } + } - if (level) insertPath[level - 1].children.push(newNode); - else this._splitRoot(node, newNode); - }, + if (!hostlessProtocol[proto] && + (slashes || (proto && !slashedProtocol[proto]))) { - _splitRoot: function (node, newNode) { - // split root node - this.data = { - children: [node, newNode], - height: node.height + 1, - bbox: null, - leaf: false - }; - calcBBox(this.data, this.toBBox); - }, + // there's a hostname. + // the first instance of /, ?, ;, or # ends the host. + // + // If there is an @ in the hostname, then non-host chars *are* allowed + // to the left of the last @ sign, unless some host-ending character + // comes *before* the @-sign. + // URLs are obnoxious. + // + // ex: + // http://a@b@c/ => user:a@b host:c + // http://a@b?@c => user:a host:c path:/?@c + + // v0.12 TODO(isaacs): This is not quite how Chrome does things. + // Review our test case against browsers more comprehensively. + + // find the first instance of any hostEndingChars + var hostEnd = -1; + for (var i = 0; i < hostEndingChars.length; i++) { + var hec = rest.indexOf(hostEndingChars[i]); + if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) + hostEnd = hec; + } + + // at this point, either we have an explicit point where the + // auth portion cannot go past, or the last @ char is the decider. + var auth, atSign; + if (hostEnd === -1) { + // atSign can be anywhere. + atSign = rest.lastIndexOf('@'); + } else { + // atSign must be in auth portion. + // http://a@b/c@d => host:b auth:a path:/c@d + atSign = rest.lastIndexOf('@', hostEnd); + } + + // Now we have a portion which is definitely the auth. + // Pull that off. + if (atSign !== -1) { + auth = rest.slice(0, atSign); + rest = rest.slice(atSign + 1); + this.auth = decodeURIComponent(auth); + } + + // the host is the remaining to the left of the first non-host char + hostEnd = -1; + for (var i = 0; i < nonHostChars.length; i++) { + var hec = rest.indexOf(nonHostChars[i]); + if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) + hostEnd = hec; + } + // if we still have not hit it, then the entire thing is a host. + if (hostEnd === -1) + hostEnd = rest.length; + + this.host = rest.slice(0, hostEnd); + rest = rest.slice(hostEnd); + + // pull out port. + this.parseHost(); + + // we've indicated that there is a hostname, + // so even if it's empty, it has to be present. + this.hostname = this.hostname || ''; + + // if hostname begins with [ and ends with ] + // assume that it's an IPv6 address. + var ipv6Hostname = this.hostname[0] === '[' && + this.hostname[this.hostname.length - 1] === ']'; + + // validate a little. + if (!ipv6Hostname) { + var hostparts = this.hostname.split(/\./); + for (var i = 0, l = hostparts.length; i < l; i++) { + var part = hostparts[i]; + if (!part) continue; + if (!part.match(hostnamePartPattern)) { + var newpart = ''; + for (var j = 0, k = part.length; j < k; j++) { + if (part.charCodeAt(j) > 127) { + // we replace non-ASCII char with a temporary placeholder + // we need this to make sure size of hostname is not + // broken by replacing non-ASCII by nothing + newpart += 'x'; + } else { + newpart += part[j]; + } + } + // we test again with ASCII char only + if (!newpart.match(hostnamePartPattern)) { + var validParts = hostparts.slice(0, i); + var notHost = hostparts.slice(i + 1); + var bit = part.match(hostnamePartStart); + if (bit) { + validParts.push(bit[1]); + notHost.unshift(bit[2]); + } + if (notHost.length) { + rest = '/' + notHost.join('.') + rest; + } + this.hostname = validParts.join('.'); + break; + } + } + } + } - _chooseSplitIndex: function (node, m, M) { + if (this.hostname.length > hostnameMaxLen) { + this.hostname = ''; + } else { + // hostnames are always lower case. + this.hostname = this.hostname.toLowerCase(); + } - var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index; + if (!ipv6Hostname) { + // IDNA Support: Returns a punycoded representation of "domain". + // It only converts parts of the domain name that + // have non-ASCII characters, i.e. it doesn't matter if + // you call it with a domain that already is ASCII-only. + this.hostname = punycode.toASCII(this.hostname); + } - minOverlap = minArea = Infinity; + var p = this.port ? ':' + this.port : ''; + var h = this.hostname || ''; + this.host = h + p; + this.href += this.host; - for (i = m; i <= M - m; i++) { - bbox1 = distBBox(node, 0, i, this.toBBox); - bbox2 = distBBox(node, i, M, this.toBBox); + // strip [ and ] from the hostname + // the host field still retains them, though + if (ipv6Hostname) { + this.hostname = this.hostname.substr(1, this.hostname.length - 2); + if (rest[0] !== '/') { + rest = '/' + rest; + } + } + } - overlap = intersectionArea(bbox1, bbox2); - area = bboxArea(bbox1) + bboxArea(bbox2); + // now rest is set to the post-host stuff. + // chop off any delim chars. + if (!unsafeProtocol[lowerProto]) { - // choose distribution with minimum overlap - if (overlap < minOverlap) { - minOverlap = overlap; - index = i; + // First, make 100% sure that any "autoEscape" chars get + // escaped, even if encodeURIComponent doesn't think they + // need to be. + for (var i = 0, l = autoEscape.length; i < l; i++) { + var ae = autoEscape[i]; + if (rest.indexOf(ae) === -1) + continue; + var esc = encodeURIComponent(ae); + if (esc === ae) { + esc = escape(ae); + } + rest = rest.split(ae).join(esc); + } + } - minArea = area < minArea ? area : minArea; - } else if (overlap === minOverlap) { - // otherwise choose distribution with minimum area - if (area < minArea) { - minArea = area; - index = i; - } - } - } + // chop off from the tail first. + var hash = rest.indexOf('#'); + if (hash !== -1) { + // got a fragment string. + this.hash = rest.substr(hash); + rest = rest.slice(0, hash); + } + var qm = rest.indexOf('?'); + if (qm !== -1) { + this.search = rest.substr(qm); + this.query = rest.substr(qm + 1); + if (parseQueryString) { + this.query = querystring.parse(this.query); + } + rest = rest.slice(0, qm); + } else if (parseQueryString) { + // no query string, but parseQueryString still requested + this.search = ''; + this.query = {}; + } + if (rest) this.pathname = rest; + if (slashedProtocol[lowerProto] && + this.hostname && !this.pathname) { + this.pathname = '/'; + } - return index; - }, + //to support http.request + if (this.pathname || this.search) { + var p = this.pathname || ''; + var s = this.search || ''; + this.path = p + s; + } - // sorts node children by the best axis for split - _chooseSplitAxis: function (node, m, M) { + // finally, reconstruct the href based on what has been validated. + this.href = this.format(); + return this; +}; - 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); +// format a parsed object into a url string +function urlFormat(obj) { + // ensure it's an object, and not a string url. + // If it's an obj, this is a no-op. + // this way, you can call url_format() on strings + // to clean up potentially wonky urls. + if (util.isString(obj)) obj = urlParse(obj); + if (!(obj instanceof Url)) return Url.prototype.format.call(obj); + return obj.format(); +} - // 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); - }, +Url.prototype.format = function() { + var auth = this.auth || ''; + if (auth) { + auth = encodeURIComponent(auth); + auth = auth.replace(/%3A/i, ':'); + auth += '@'; + } - // total margin of all possible split distributions where each node is at least m full - _allDistMargin: function (node, m, M, compare) { + var protocol = this.protocol || '', + pathname = this.pathname || '', + hash = this.hash || '', + host = false, + query = ''; + + if (this.host) { + host = auth + this.host; + } else if (this.hostname) { + host = auth + (this.hostname.indexOf(':') === -1 ? + this.hostname : + '[' + this.hostname + ']'); + if (this.port) { + host += ':' + this.port; + } + } - node.children.sort(compare); + if (this.query && + util.isObject(this.query) && + Object.keys(this.query).length) { + query = querystring.stringify(this.query); + } - var toBBox = this.toBBox, - leftBBox = distBBox(node, 0, m, toBBox), - rightBBox = distBBox(node, M - m, M, toBBox), - margin = bboxMargin(leftBBox) + bboxMargin(rightBBox), - i, child; + var search = this.search || (query && ('?' + query)) || ''; - for (i = m; i < M - m; i++) { - child = node.children[i]; - extend(leftBBox, node.leaf ? toBBox(child) : child.bbox); - margin += bboxMargin(leftBBox); - } + if (protocol && protocol.substr(-1) !== ':') protocol += ':'; - for (i = M - m - 1; i >= m; i--) { - child = node.children[i]; - extend(rightBBox, node.leaf ? toBBox(child) : child.bbox); - margin += bboxMargin(rightBBox); - } + // only the slashedProtocols get the //. Not mailto:, xmpp:, etc. + // unless they had them to begin with. + if (this.slashes || + (!protocol || slashedProtocol[protocol]) && host !== false) { + host = '//' + (host || ''); + if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname; + } else if (!host) { + host = ''; + } - return margin; - }, + if (hash && hash.charAt(0) !== '#') hash = '#' + hash; + if (search && search.charAt(0) !== '?') search = '?' + search; - _adjustParentBBoxes: function (bbox, path, level) { - // adjust bboxes along the given tree path - for (var i = level; i >= 0; i--) { - extend(path[i].bbox, bbox); - } - }, + pathname = pathname.replace(/[?#]/g, function(match) { + return encodeURIComponent(match); + }); + search = search.replace('#', '%23'); - _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); + return protocol + host + pathname + search + hash; +}; - } else this.clear(); +function urlResolve(source, relative) { + return urlParse(source, false, true).resolve(relative); +} - } else calcBBox(path[i], this.toBBox); - } - }, +Url.prototype.resolve = function(relative) { + return this.resolveObject(urlParse(relative, false, true)).format(); +}; - _initFormat: function (format) { - // data format (minX, minY, maxX, maxY accessors) +function urlResolveObject(source, relative) { + if (!source) return relative; + return urlParse(source, false, true).resolveObject(relative); +} - // 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 +Url.prototype.resolveObject = function(relative) { + if (util.isString(relative)) { + var rel = new Url(); + rel.parse(relative, false, true); + relative = rel; + } - // jshint evil: true + var result = new Url(); + var tkeys = Object.keys(this); + for (var tk = 0; tk < tkeys.length; tk++) { + var tkey = tkeys[tk]; + result[tkey] = this[tkey]; + } - var compareArr = ['return a', ' - b', ';']; + // hash is always overridden, no matter what. + // even href="" will remove it. + result.hash = relative.hash; - this.compareMinX = new Function('a', 'b', compareArr.join(format[0])); - this.compareMinY = new Function('a', 'b', compareArr.join(format[1])); + // if the relative url is empty, then there's nothing left to do here. + if (relative.href === '') { + result.href = result.format(); + return result; + } - this.toBBox = new Function('a', 'return [a' + format.join(', a') + '];'); + // hrefs like //foo/bar always cut to the protocol. + if (relative.slashes && !relative.protocol) { + // take everything except the protocol from relative + var rkeys = Object.keys(relative); + for (var rk = 0; rk < rkeys.length; rk++) { + var rkey = rkeys[rk]; + if (rkey !== 'protocol') + result[rkey] = relative[rkey]; } -}; - - -// calculate node's bbox from bboxes of its children -function calcBBox(node, toBBox) { - node.bbox = distBBox(node, 0, node.children.length, toBBox); -} - -// min bounding rectangle of node children from k to p-1 -function distBBox(node, k, p, toBBox) { - var bbox = empty(); - for (var i = k, child; i < p; i++) { - child = node.children[i]; - extend(bbox, node.leaf ? toBBox(child) : child.bbox); + //urlParse appends trailing / to urls like http://www.example.com + if (slashedProtocol[result.protocol] && + result.hostname && !result.pathname) { + result.path = result.pathname = '/'; } - return bbox; -} + result.href = result.format(); + return result; + } -function empty() { return [Infinity, Infinity, -Infinity, -Infinity]; } + if (relative.protocol && relative.protocol !== result.protocol) { + // if it's a known url protocol, then changing + // the protocol does weird things + // first, if it's not file:, then we MUST have a host, + // and if there was a path + // to begin with, then we MUST have a path. + // if it is file:, then the host is dropped, + // because that's known to be hostless. + // anything else is assumed to be absolute. + if (!slashedProtocol[relative.protocol]) { + var keys = Object.keys(relative); + for (var v = 0; v < keys.length; v++) { + var k = keys[v]; + result[k] = relative[k]; + } + result.href = result.format(); + return result; + } + + result.protocol = relative.protocol; + if (!relative.host && !hostlessProtocol[relative.protocol]) { + var relPath = (relative.pathname || '').split('/'); + while (relPath.length && !(relative.host = relPath.shift())); + if (!relative.host) relative.host = ''; + if (!relative.hostname) relative.hostname = ''; + if (relPath[0] !== '') relPath.unshift(''); + if (relPath.length < 2) relPath.unshift(''); + result.pathname = relPath.join('/'); + } else { + result.pathname = relative.pathname; + } + result.search = relative.search; + result.query = relative.query; + result.host = relative.host || ''; + result.auth = relative.auth; + result.hostname = relative.hostname || relative.host; + result.port = relative.port; + // to support http.request + if (result.pathname || result.search) { + var p = result.pathname || ''; + var s = result.search || ''; + result.path = p + s; + } + result.slashes = result.slashes || relative.slashes; + result.href = result.format(); + return result; + } -function extend(a, b) { - a[0] = Math.min(a[0], b[0]); - a[1] = Math.min(a[1], b[1]); - a[2] = Math.max(a[2], b[2]); - a[3] = Math.max(a[3], b[3]); - return a; -} + var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'), + isRelAbs = ( + relative.host || + relative.pathname && relative.pathname.charAt(0) === '/' + ), + mustEndAbs = (isRelAbs || isSourceAbs || + (result.host && relative.pathname)), + removeAllDots = mustEndAbs, + srcPath = result.pathname && result.pathname.split('/') || [], + relPath = relative.pathname && relative.pathname.split('/') || [], + psychotic = result.protocol && !slashedProtocol[result.protocol]; + + // if the url is a non-slashed url, then relative + // links like ../.. should be able + // to crawl up to the hostname, as well. This is strange. + // result.protocol has already been set by now. + // Later on, put the first path part into the host field. + if (psychotic) { + result.hostname = ''; + result.port = null; + if (result.host) { + if (srcPath[0] === '') srcPath[0] = result.host; + else srcPath.unshift(result.host); + } + result.host = ''; + if (relative.protocol) { + relative.hostname = null; + relative.port = null; + if (relative.host) { + if (relPath[0] === '') relPath[0] = relative.host; + else relPath.unshift(relative.host); + } + relative.host = null; + } + mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === ''); + } -function compareNodeMinX(a, b) { return a.bbox[0] - b.bbox[0]; } -function compareNodeMinY(a, b) { return a.bbox[1] - b.bbox[1]; } + if (isRelAbs) { + // it's absolute. + result.host = (relative.host || relative.host === '') ? + relative.host : result.host; + result.hostname = (relative.hostname || relative.hostname === '') ? + relative.hostname : result.hostname; + result.search = relative.search; + result.query = relative.query; + srcPath = relPath; + // fall through to the dot-handling below. + } else if (relPath.length) { + // it's relative + // throw away the existing file, and take the new path instead. + if (!srcPath) srcPath = []; + srcPath.pop(); + srcPath = srcPath.concat(relPath); + result.search = relative.search; + result.query = relative.query; + } else if (!util.isNullOrUndefined(relative.search)) { + // just pull out the search. + // like href='?foo'. + // Put this after the other two cases because it simplifies the booleans + if (psychotic) { + result.hostname = result.host = srcPath.shift(); + //occationaly the auth can get stuck only in host + //this especially happens in cases like + //url.resolveObject('mailto:local1@domain1', 'local2@domain2') + var authInHost = result.host && result.host.indexOf('@') > 0 ? + result.host.split('@') : false; + if (authInHost) { + result.auth = authInHost.shift(); + result.host = result.hostname = authInHost.shift(); + } + } + result.search = relative.search; + result.query = relative.query; + //to support http.request + if (!util.isNull(result.pathname) || !util.isNull(result.search)) { + result.path = (result.pathname ? result.pathname : '') + + (result.search ? result.search : ''); + } + result.href = result.format(); + return result; + } -function bboxArea(a) { return (a[2] - a[0]) * (a[3] - a[1]); } -function bboxMargin(a) { return (a[2] - a[0]) + (a[3] - a[1]); } + if (!srcPath.length) { + // no path at all. easy. + // we've already handled the other stuff above. + result.pathname = null; + //to support http.request + if (result.search) { + result.path = '/' + result.search; + } else { + result.path = null; + } + result.href = result.format(); + return result; + } -function enlargedArea(a, b) { - return (Math.max(b[2], a[2]) - Math.min(b[0], a[0])) * - (Math.max(b[3], a[3]) - Math.min(b[1], a[1])); -} + // if a url ENDs in . or .., then it must get a trailing slash. + // however, if it ends in anything else non-slashy, + // then it must NOT get a trailing slash. + var last = srcPath.slice(-1)[0]; + var hasTrailingSlash = ( + (result.host || relative.host || srcPath.length > 1) && + (last === '.' || last === '..') || last === ''); -function intersectionArea(a, b) { - var minX = Math.max(a[0], b[0]), - minY = Math.max(a[1], b[1]), - maxX = Math.min(a[2], b[2]), - maxY = Math.min(a[3], b[3]); + // strip single dots, resolve double dots to parent dir + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = srcPath.length; i >= 0; i--) { + last = srcPath[i]; + if (last === '.') { + srcPath.splice(i, 1); + } else if (last === '..') { + srcPath.splice(i, 1); + up++; + } else if (up) { + srcPath.splice(i, 1); + up--; + } + } - return Math.max(0, maxX - minX) * - Math.max(0, maxY - minY); -} + // if the path is allowed to go above the root, restore leading ..s + if (!mustEndAbs && !removeAllDots) { + for (; up--; up) { + srcPath.unshift('..'); + } + } -function contains(a, b) { - return a[0] <= b[0] && - a[1] <= b[1] && - b[2] <= a[2] && - b[3] <= a[3]; -} + if (mustEndAbs && srcPath[0] !== '' && + (!srcPath[0] || srcPath[0].charAt(0) !== '/')) { + srcPath.unshift(''); + } -function intersects(a, b) { - return b[0] <= a[2] && - b[1] <= a[3] && - b[2] >= a[0] && - b[3] >= a[1]; -} + if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) { + srcPath.push(''); + } -// 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 + var isAbsolute = srcPath[0] === '' || + (srcPath[0] && srcPath[0].charAt(0) === '/'); + + // put the host back + if (psychotic) { + result.hostname = result.host = isAbsolute ? '' : + srcPath.length ? srcPath.shift() : ''; + //occationaly the auth can get stuck only in host + //this especially happens in cases like + //url.resolveObject('mailto:local1@domain1', 'local2@domain2') + var authInHost = result.host && result.host.indexOf('@') > 0 ? + result.host.split('@') : false; + if (authInHost) { + result.auth = authInHost.shift(); + result.host = result.hostname = authInHost.shift(); + } + } -function multiSelect(arr, left, right, n, compare) { - var stack = [left, right], - mid; + mustEndAbs = mustEndAbs || (result.host && srcPath.length); - while (stack.length) { - right = stack.pop(); - left = stack.pop(); + if (mustEndAbs && !isAbsolute) { + srcPath.unshift(''); + } - if (right - left <= n) continue; + if (!srcPath.length) { + result.pathname = null; + result.path = null; + } else { + result.pathname = srcPath.join('/'); + } - mid = left + Math.ceil((right - left) / n / 2) * n; - select(arr, left, right, mid, compare); + //to support request.http + if (!util.isNull(result.pathname) || !util.isNull(result.search)) { + result.path = (result.pathname ? result.pathname : '') + + (result.search ? result.search : ''); + } + result.auth = relative.auth || result.auth; + result.slashes = result.slashes || relative.slashes; + result.href = result.format(); + return result; +}; - stack.push(left, mid, mid, right); +Url.prototype.parseHost = function() { + var host = this.host; + var port = portPattern.exec(host); + if (port) { + port = port[0]; + if (port !== ':') { + this.port = port.substr(1); } -} + host = host.substr(0, host.length - port.length); + } + if (host) this.hostname = host; +}; -// Floyd-Rivest selection algorithm: -// sort an array between left and right (inclusive) so that the smallest k elements come first (unordered) -function select(arr, left, right, k, compare) { - var n, i, z, s, sd, newLeft, newRight, t, j; +},{"./util":208,"punycode":198,"querystring":201}],208:[function(require,module,exports){ +'use strict'; - while (right > left) { - if (right - left > 600) { - n = right - left + 1; - i = k - left + 1; - z = Math.log(n); - s = 0.5 * Math.exp(2 * z / 3); - sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (i - n / 2 < 0 ? -1 : 1); - newLeft = Math.max(left, Math.floor(k - i * s / n + sd)); - newRight = Math.min(right, Math.floor(k + (n - i) * s / n + sd)); - select(arr, newLeft, newRight, k, compare); - } +module.exports = { + isString: function(arg) { + return typeof(arg) === 'string'; + }, + isObject: function(arg) { + return typeof(arg) === 'object' && arg !== null; + }, + isNull: function(arg) { + return arg === null; + }, + isNullOrUndefined: function(arg) { + return arg == null; + } +}; - t = arr[k]; - i = left; - j = right; +},{}],209:[function(require,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} - swap(arr, left, k); - if (compare(arr[right], t) > 0) swap(arr, left, right); +},{}],210:[function(require,module,exports){ +module.exports = function isBuffer(arg) { + return arg && typeof arg === 'object' + && typeof arg.copy === 'function' + && typeof arg.fill === 'function' + && typeof arg.readUInt8 === 'function'; +} +},{}],211:[function(require,module,exports){ +(function (process,global){ +// 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. - while (i < j) { - swap(arr, i, j); - i++; - j--; - while (compare(arr[i], t) < 0) i++; - while (compare(arr[j], t) > 0) j--; - } +var formatRegExp = /%[sdj%]/g; +exports.format = function(f) { + if (!isString(f)) { + var objects = []; + for (var i = 0; i < arguments.length; i++) { + objects.push(inspect(arguments[i])); + } + return objects.join(' '); + } - if (compare(arr[left], t) === 0) swap(arr, left, j); - else { - j++; - swap(arr, j, right); + var i = 1; + var args = arguments; + var len = args.length; + var str = String(f).replace(formatRegExp, function(x) { + if (x === '%%') return '%'; + if (i >= len) return x; + switch (x) { + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); + case '%j': + try { + return JSON.stringify(args[i++]); + } catch (_) { + return '[Circular]'; } - - if (j <= k) left = j + 1; - if (k <= j) right = j - 1; + default: + return x; } -} + }); + for (var x = args[i]; i < len; x = args[++i]) { + if (isNull(x) || !isObject(x)) { + str += ' ' + x; + } else { + str += ' ' + inspect(x); + } + } + return str; +}; -function swap(arr, i, j) { - var tmp = arr[i]; - arr[i] = arr[j]; - arr[j] = tmp; -} +// Mark that a method should not be used. +// Returns a modified function which warns once by default. +// If --no-deprecation is set, then it is a no-op. +exports.deprecate = function(fn, msg) { + // Allow for deprecating things in the process of starting up. + if (isUndefined(global.process)) { + return function() { + return exports.deprecate(fn, msg).apply(this, arguments); + }; + } -// export as AMD/CommonJS module or global variable -if (typeof define === 'function' && define.amd) define('rbush', function () { return rbush; }); -else if (typeof module !== 'undefined') module.exports = rbush; -else if (typeof self !== 'undefined') self.rbush = rbush; -else window.rbush = rbush; + if (process.noDeprecation === true) { + return fn; + } -})(); + var warned = false; + function deprecated() { + if (!warned) { + if (process.throwDeprecation) { + throw new Error(msg); + } else if (process.traceDeprecation) { + console.trace(msg); + } else { + console.error(msg); + } + warned = true; + } + return fn.apply(this, arguments); + } -},{}],164:[function(require,module,exports){ -// Copyright 2014 Simon Lydell -// X11 (“MIT”) Licensed. (See LICENSE.) - -void (function(root, factory) { - if (typeof define === "function" && define.amd) { - define(factory) - } else if (typeof exports === "object") { - module.exports = factory() - } else { - root.resolveUrl = factory() - } -}(this, function() { - - function resolveUrl(/* ...urls */) { - var numUrls = arguments.length - - if (numUrls === 0) { - throw new Error("resolveUrl requires at least one argument; got none.") - } - - var base = document.createElement("base") - base.href = arguments[0] - - if (numUrls === 1) { - return base.href - } - - var head = document.getElementsByTagName("head")[0] - head.insertBefore(base, head.firstChild) - - var a = document.createElement("a") - var resolved - - for (var index = 1; index < numUrls; index++) { - a.href = arguments[index] - resolved = a.href - base.href = resolved - } - - head.removeChild(base) - - return resolved - } - - return resolveUrl - -})); + return deprecated; +}; -},{}],165:[function(require,module,exports){ -'use strict'; -module.exports = ShelfPack; +var debugs = {}; +var debugEnviron; +exports.debuglog = function(set) { + if (isUndefined(debugEnviron)) + debugEnviron = process.env.NODE_DEBUG || ''; + set = set.toUpperCase(); + if (!debugs[set]) { + if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { + var pid = process.pid; + debugs[set] = function() { + var msg = exports.format.apply(exports, arguments); + console.error('%s %d: %s', set, pid, msg); + }; + } else { + debugs[set] = function() {}; + } + } + return debugs[set]; +}; + /** - * Uses the Shelf Best Height Fit algorithm from - * http://clb.demon.fi/files/RectangleBinPack.pdf - * @private + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Object} opts Optional options object that alters the output. */ -function ShelfPack(width, height) { - this.width = width; - this.height = height; - this.shelves = []; - this.stats = {}; - this.count = function(h) { - this.stats[h] = (this.stats[h] | 0) + 1; - }; -} - -ShelfPack.prototype.allocate = function(reqWidth, reqHeight) { - var y = 0, - best = { shelf: -1, waste: Infinity }, - shelf, waste; - - // find shelf - for (var i = 0; i < this.shelves.length; i++) { - shelf = this.shelves[i]; - y += shelf.height; - - // exactly the right height with width to spare, pack it.. - if (reqHeight === shelf.height && reqWidth <= shelf.free) { - this.count(reqHeight); - return shelf.alloc(reqWidth, reqHeight); - } - // not enough height or width, skip it.. - if (reqHeight > shelf.height || reqWidth > shelf.free) { - continue; - } - // maybe enough height or width, minimize waste.. - if (reqHeight < shelf.height && reqWidth <= shelf.free) { - waste = shelf.height - reqHeight; - if (waste < best.waste) { - best.waste = waste; - best.shelf = i; - } - } - } +/* legacy: obj, showHidden, depth, colors*/ +function inspect(obj, opts) { + // default options + var ctx = { + seen: [], + stylize: stylizeNoColor + }; + // legacy... + if (arguments.length >= 3) ctx.depth = arguments[2]; + if (arguments.length >= 4) ctx.colors = arguments[3]; + if (isBoolean(opts)) { + // legacy... + ctx.showHidden = opts; + } else if (opts) { + // got an "options" object + exports._extend(ctx, opts); + } + // set default options + if (isUndefined(ctx.showHidden)) ctx.showHidden = false; + if (isUndefined(ctx.depth)) ctx.depth = 2; + if (isUndefined(ctx.colors)) ctx.colors = false; + if (isUndefined(ctx.customInspect)) ctx.customInspect = true; + if (ctx.colors) ctx.stylize = stylizeWithColor; + return formatValue(ctx, obj, ctx.depth); +} +exports.inspect = inspect; - if (best.shelf !== -1) { - shelf = this.shelves[best.shelf]; - this.count(reqHeight); - return shelf.alloc(reqWidth, reqHeight); - } - // add shelf - if (reqHeight <= (this.height - y) && reqWidth <= this.width) { - shelf = new Shelf(y, this.width, reqHeight); - this.shelves.push(shelf); - this.count(reqHeight); - return shelf.alloc(reqWidth, reqHeight); - } +// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +inspect.colors = { + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [30, 39], + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39] +}; - // no more space - return {x: -1, y: -1}; +// Don't use 'blue' not visible on cmd.exe +inspect.styles = { + 'special': 'cyan', + 'number': 'yellow', + 'boolean': 'yellow', + 'undefined': 'grey', + 'null': 'bold', + 'string': 'green', + 'date': 'magenta', + // "name": intentionally not styling + 'regexp': 'red' }; -ShelfPack.prototype.resize = function(reqWidth, reqHeight) { - if (reqWidth < this.width || reqHeight < this.height) { return false; } - this.height = reqHeight; - this.width = reqWidth; - for (var i = 0; i < this.shelves.length; i++) { - this.shelves[i].resize(reqWidth); - } - return true; -}; +function stylizeWithColor(str, styleType) { + var style = inspect.styles[styleType]; + + if (style) { + return '\u001b[' + inspect.colors[style][0] + 'm' + str + + '\u001b[' + inspect.colors[style][1] + 'm'; + } else { + return str; + } +} -function Shelf(y, width, height) { - this.y = y; - this.x = 0; - this.width = this.free = width; - this.height = height; +function stylizeNoColor(str, styleType) { + return str; } -Shelf.prototype = { - alloc: function(reqWidth, reqHeight) { - if (reqWidth > this.free || reqHeight > this.height) { - return {x: -1, y: -1}; - } - var x = this.x; - this.x += reqWidth; - this.free -= reqWidth; - return {x: x, y: this.y, w: reqWidth, h: reqHeight}; - }, - resize: function(reqWidth) { - if (reqWidth < this.width) { return false; } - this.free += (reqWidth - this.width); - this.width = reqWidth; - return true; - } -}; +function arrayToHash(array) { + var hash = {}; + array.forEach(function(val, idx) { + hash[val] = true; + }); -},{}],166:[function(require,module,exports){ -'use strict'; + return hash; +} -var rbush = require('rbush'); -module.exports = supercluster; +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (ctx.customInspect && + value && + isFunction(value.inspect) && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes, ctx); + if (!isString(ret)) { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; + } -function supercluster(options) { - return new SuperCluster(options); -} + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } -function SuperCluster(options) { - this.options = extend(Object.create(this.options), options); - this._initTrees(); -} + // Look up the keys of the object. + var keys = Object.keys(value); + var visibleKeys = arrayToHash(keys); -SuperCluster.prototype = { - options: { - minZoom: 0, // min zoom to generate clusters on - maxZoom: 16, // max zoom level to cluster the points on - radius: 40, // cluster radius in pixels - extent: 512, // tile extent (radius is calculated relative to it) - nodeSize: 16, // size of the R-tree leaf node, affects performance - log: false // whether to log timing info - }, + if (ctx.showHidden) { + keys = Object.getOwnPropertyNames(value); + } - load: function (points) { - var log = this.options.log; + // IE doesn't make error fields non-enumerable + // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx + if (isError(value) + && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { + return formatError(value); + } - if (log) console.time('total time'); + // Some type of object without properties can be shortcutted. + if (keys.length === 0) { + if (isFunction(value)) { + var name = value.name ? ': ' + value.name : ''; + return ctx.stylize('[Function' + name + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } - var timerId = 'prepare ' + points.length + ' points'; - if (log) console.time(timerId); + var base = '', array = false, braces = ['{', '}']; - // generate a cluster object for each point - var clusters = points.map(createPointCluster); - if (log) console.timeEnd(timerId); + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } - // cluster points on max zoom, then cluster the results on previous zoom, etc.; - // results in a cluster hierarchy across zoom levels - for (var z = this.options.maxZoom; z >= this.options.minZoom; z--) { - var now = +Date.now(); + // Make functions say that they are functions + if (isFunction(value)) { + var n = value.name ? ': ' + value.name : ''; + base = ' [Function' + n + ']'; + } - this.trees[z + 1].load(clusters); // index input points into an R-tree - clusters = this._cluster(clusters, z); // create a new set of clusters for the zoom + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } - if (log) console.log('z%d: %d clusters in %dms', z, clusters.length, +Date.now() - now); - } - this.trees[this.options.minZoom].load(clusters); // index top-level clusters + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } - if (log) console.timeEnd('total time'); + // Make error with message first say the error + if (isError(value)) { + base = ' ' + formatError(value); + } - return this; - }, + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } - getClusters: function (bbox, zoom) { - var projBBox = [lngX(bbox[0]), latY(bbox[3]), lngX(bbox[2]), latY(bbox[1])]; - var z = Math.max(this.options.minZoom, Math.min(zoom, this.options.maxZoom + 1)); - var clusters = this.trees[z].search(projBBox); - return clusters.map(getClusterJSON); - }, + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } + } - getTile: function (z, x, y) { - var z2 = Math.pow(2, z); - var extent = this.options.extent; - var p = this.options.radius / extent; - var clusters = this.trees[z].search([ - (x - p) / z2, - (y - p) / z2, - (x + 1 + p) / z2, - (y + 1 + p) / z2 - ]); - if (!clusters.length) return null; - var tile = { - features: [] - }; - for (var i = 0; i < clusters.length; i++) { - var c = clusters[i]; - var feature = { - type: 1, - geometry: [[ - Math.round(extent * (c.wx * z2 - x)), - Math.round(extent * (c.wy * z2 - y)) - ]], - tags: c.point ? c.point.properties : getClusterProperties(c) - }; - tile.features.push(feature); - } - return tile; - }, + ctx.seen.push(value); - _initTrees: function () { - this.trees = []; - // make an R-Tree index for each zoom level - for (var z = 0; z <= this.options.maxZoom + 1; z++) { - this.trees[z] = rbush(this.options.nodeSize); - this.trees[z].toBBox = toBBox; - this.trees[z].compareMinX = compareMinX; - this.trees[z].compareMinY = compareMinY; - } - }, + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } - _cluster: function (points, zoom) { - var clusters = []; - var r = this.options.radius / (this.options.extent * Math.pow(2, zoom)); - var bbox = [0, 0, 0, 0]; + ctx.seen.pop(); - // loop through each point - for (var i = 0; i < points.length; i++) { - var p = points[i]; - // if we've already visited the point at this zoom level, skip it - if (p.zoom <= zoom) continue; - p.zoom = zoom; + return reduceToSingleString(output, base, braces); +} - // find all nearby points with a bbox search - bbox[0] = p.wx - r; - bbox[1] = p.wy - r; - bbox[2] = p.wx + r; - bbox[3] = p.wy + r; - var bboxNeighbors = this.trees[zoom + 1].search(bbox); - var foundNeighbors = false; - var numPoints = p.numPoints; - var wx = p.wx * numPoints; - var wy = p.wy * numPoints; +function formatPrimitive(ctx, value) { + if (isUndefined(value)) + return ctx.stylize('undefined', 'undefined'); + if (isString(value)) { + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + } + if (isNumber(value)) + return ctx.stylize('' + value, 'number'); + if (isBoolean(value)) + return ctx.stylize('' + value, 'boolean'); + // For some reason typeof null is "object", so special case here. + if (isNull(value)) + return ctx.stylize('null', 'null'); +} - for (var j = 0; j < bboxNeighbors.length; j++) { - var b = bboxNeighbors[j]; - // filter out neighbors that are too far or already processed - if (zoom < b.zoom && distSq(p, b) <= r * r) { - foundNeighbors = true; - b.zoom = zoom; // save the zoom (so it doesn't get processed twice) - wx += b.wx * b.numPoints; // accumulate coordinates for calculating weighted center - wy += b.wy * b.numPoints; - numPoints += b.numPoints; - } - } - if (!foundNeighbors) { - clusters.push(p); // no neighbors, add a single point as cluster - continue; - } +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; +} - // form a cluster with neighbors - var cluster = createCluster(p.x, p.y); - cluster.numPoints = numPoints; - // save weighted cluster center for display - cluster.wx = wx / numPoints; - cluster.wy = wy / numPoints; +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (hasOwnProperty(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); + } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; +} - clusters.push(cluster); - } - return clusters; +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str, desc; + desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; + if (desc.get) { + if (desc.set) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); } -}; + } else { + if (desc.set) { + str = ctx.stylize('[Setter]', 'special'); + } + } + if (!hasOwnProperty(visibleKeys, key)) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(desc.value) < 0) { + if (isNull(recurseTimes)) { + str = formatValue(ctx, desc.value, null); + } else { + str = formatValue(ctx, desc.value, recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (isUndefined(name)) { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); + } + } -function toBBox(p) { - return [p.x, p.y, p.x, p.y]; -} -function compareMinX(a, b) { - return a.x - b.x; -} -function compareMinY(a, b) { - return a.y - b.y; + return name + ': ' + str; } -function createCluster(x, y) { - return { - x: x, // cluster center - y: y, - wx: x, // weighted cluster center - wy: y, - zoom: Infinity, // the last zoom the cluster was processed at - point: null, - numPoints: 1 - }; -} -function createPointCluster(p) { - var coords = p.geometry.coordinates; - var cluster = createCluster(lngX(coords[0]), latY(coords[1])); - cluster.point = p; - return cluster; -} +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; + }, 0); -function getClusterJSON(cluster) { - return cluster.point ? cluster.point : { - type: 'Feature', - properties: getClusterProperties(cluster), - geometry: { - type: 'Point', - coordinates: [xLng(cluster.wx), yLat(cluster.wy)] - } - }; -} + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } -function getClusterProperties(cluster) { - var count = cluster.numPoints; - var abbrev = count >= 10000 ? Math.round(count / 1000) + 'k' : - count >= 1000 ? (Math.round(count / 100) / 10) + 'k' : count; - return { - cluster: true, - point_count: count, - point_count_abbreviated: abbrev - }; + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; } -// longitude/latitude to spherical mercator in [0..1] range -function lngX(lng) { - return lng / 360 + 0.5; + +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. +function isArray(ar) { + return Array.isArray(ar); } -function latY(lat) { - var sin = Math.sin(lat * Math.PI / 180), - y = (0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI); - return y < 0 ? 0 : - y > 1 ? 1 : y; +exports.isArray = isArray; + +function isBoolean(arg) { + return typeof arg === 'boolean'; } +exports.isBoolean = isBoolean; -// spherical mercator to longitude/latitude -function xLng(x) { - return (x - 0.5) * 360; +function isNull(arg) { + return arg === null; } -function yLat(y) { - var y2 = (180 - y * 360) * Math.PI / 180; - return 360 * Math.atan(Math.exp(y2)) / Math.PI - 90; +exports.isNull = isNull; + +function isNullOrUndefined(arg) { + return arg == null; } +exports.isNullOrUndefined = isNullOrUndefined; -// squared distance between two points -function distSq(a, b) { - var dx = a.wx - b.wx; - var dy = a.wy - b.wy; - return dx * dx + dy * dy; +function isNumber(arg) { + return typeof arg === 'number'; } +exports.isNumber = isNumber; -function extend(dest, src) { - for (var id in src) dest[id] = src[id]; - return dest; +function isString(arg) { + return typeof arg === 'string'; } +exports.isString = isString; -},{"rbush":163}],167:[function(require,module,exports){ -/* - * Copyright (C) 2008 Apple Inc. 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. - * - * Ported from Webkit - * http://svn.webkit.org/repository/webkit/trunk/Source/WebCore/platform/graphics/UnitBezier.h - */ +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; -module.exports = UnitBezier; +function isUndefined(arg) { + return arg === void 0; +} +exports.isUndefined = isUndefined; -function UnitBezier(p1x, p1y, p2x, p2y) { - // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1). - this.cx = 3.0 * p1x; - this.bx = 3.0 * (p2x - p1x) - this.cx; - this.ax = 1.0 - this.cx - this.bx; +function isRegExp(re) { + return isObject(re) && objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; - this.cy = 3.0 * p1y; - this.by = 3.0 * (p2y - p1y) - this.cy; - this.ay = 1.0 - this.cy - this.by; +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} +exports.isObject = isObject; - this.p1x = p1x; - this.p1y = p2y; - this.p2x = p2x; - this.p2y = p2y; +function isDate(d) { + return isObject(d) && objectToString(d) === '[object Date]'; } +exports.isDate = isDate; -UnitBezier.prototype.sampleCurveX = function(t) { - // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule. - return ((this.ax * t + this.bx) * t + this.cx) * t; -}; +function isError(e) { + return isObject(e) && + (objectToString(e) === '[object Error]' || e instanceof Error); +} +exports.isError = isError; -UnitBezier.prototype.sampleCurveY = function(t) { - return ((this.ay * t + this.by) * t + this.cy) * t; -}; +function isFunction(arg) { + return typeof arg === 'function'; +} +exports.isFunction = isFunction; -UnitBezier.prototype.sampleCurveDerivativeX = function(t) { - return (3.0 * this.ax * t + 2.0 * this.bx) * t + this.cx; -}; +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; -UnitBezier.prototype.solveCurveX = function(x, epsilon) { - if (typeof epsilon === 'undefined') epsilon = 1e-6; +exports.isBuffer = require('./support/isBuffer'); - var t0, t1, t2, x2, i; +function objectToString(o) { + return Object.prototype.toString.call(o); +} - // First try a few iterations of Newton's method -- normally very fast. - for (t2 = x, i = 0; i < 8; i++) { - x2 = this.sampleCurveX(t2) - x; - if (Math.abs(x2) < epsilon) return t2; +function pad(n) { + return n < 10 ? '0' + n.toString(10) : n.toString(10); +} - var d2 = this.sampleCurveDerivativeX(t2); - if (Math.abs(d2) < 1e-6) break; - t2 = t2 - x2 / d2; - } +var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', + 'Oct', 'Nov', 'Dec']; - // Fall back to the bisection method for reliability. - t0 = 0.0; - t1 = 1.0; - t2 = x; +// 26 Feb 16:19:34 +function timestamp() { + var d = new Date(); + var time = [pad(d.getHours()), + pad(d.getMinutes()), + pad(d.getSeconds())].join(':'); + return [d.getDate(), months[d.getMonth()], time].join(' '); +} - if (t2 < t0) return t0; - if (t2 > t1) return t1; - while (t0 < t1) { +// log is just a thin wrapper to console.log that prepends a timestamp +exports.log = function() { + console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); +}; - x2 = this.sampleCurveX(t2); - if (Math.abs(x2 - x) < epsilon) return t2; - if (x > x2) { - t0 = t2; - } else { - t1 = t2; - } +/** + * Inherit the prototype methods from one constructor into another. + * + * The Function.prototype.inherits from lang.js rewritten as a standalone + * function (not on Function.prototype). NOTE: If this file is to be loaded + * during bootstrapping this function needs to be rewritten using some native + * functions as prototype setup using normal JavaScript does not work as + * expected during bootstrapping (see mirror.js in r114903). + * + * @param {function} ctor Constructor function which needs to inherit the + * prototype. + * @param {function} superCtor Constructor function to inherit prototype from. + */ +exports.inherits = require('inherits'); - t2 = (t1 - t0) * 0.5 + t0; - } +exports._extend = function(origin, add) { + // Don't do anything if add isn't an object + if (!add || !isObject(add)) return origin; - // Failure. - return t2; + var keys = Object.keys(add); + var i = keys.length; + while (i--) { + origin[keys[i]] = add[keys[i]]; + } + return origin; }; -UnitBezier.prototype.solve = function(x, epsilon) { - return this.sampleCurveY(this.solveCurveX(x, epsilon)); -}; +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} -},{}],168:[function(require,module,exports){ +}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./support/isBuffer":210,"_process":197,"inherits":209}],212:[function(require,module,exports){ module.exports.VectorTile = require('./lib/vectortile.js'); module.exports.VectorTileFeature = require('./lib/vectortilefeature.js'); module.exports.VectorTileLayer = require('./lib/vectortilelayer.js'); -},{"./lib/vectortile.js":169,"./lib/vectortilefeature.js":170,"./lib/vectortilelayer.js":171}],169:[function(require,module,exports){ +},{"./lib/vectortile.js":213,"./lib/vectortilefeature.js":214,"./lib/vectortilelayer.js":215}],213:[function(require,module,exports){ 'use strict'; var VectorTileLayer = require('./vectortilelayer'); @@ -29571,7 +32132,7 @@ function readTile(tag, layers, pbf) { } -},{"./vectortilelayer":171}],170:[function(require,module,exports){ +},{"./vectortilelayer":215}],214:[function(require,module,exports){ 'use strict'; var Point = require('point-geometry'); @@ -29594,7 +32155,7 @@ function VectorTileFeature(pbf, end, extent, keys, values) { } function readFeature(tag, feature, pbf) { - if (tag == 1) feature._id = pbf.readVarint(); + if (tag == 1) feature.id = pbf.readVarint(); else if (tag == 2) readTag(pbf, feature); else if (tag == 3) feature.type = pbf.readVarint(); else if (tag == 4) feature._geometry = pbf.pos; @@ -29603,2998 +32164,822 @@ function readFeature(tag, feature, pbf) { function readTag(pbf, feature) { var end = pbf.readVarint() + pbf.pos; - while (pbf.pos < end) { - var key = feature._keys[pbf.readVarint()], - value = feature._values[pbf.readVarint()]; - feature.properties[key] = value; - } -} - -VectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon']; - -VectorTileFeature.prototype.loadGeometry = function() { - var pbf = this._pbf; - pbf.pos = this._geometry; - - var end = pbf.readVarint() + pbf.pos, - cmd = 1, - length = 0, - x = 0, - y = 0, - lines = [], - line; - - while (pbf.pos < end) { - if (!length) { - var cmdLen = pbf.readVarint(); - cmd = cmdLen & 0x7; - length = cmdLen >> 3; - } - - length--; - - if (cmd === 1 || cmd === 2) { - x += pbf.readSVarint(); - y += pbf.readSVarint(); - - if (cmd === 1) { // moveTo - if (line) lines.push(line); - line = []; - } - - line.push(new Point(x, y)); - - } else if (cmd === 7) { - - // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90 - if (line) { - line.push(line[0].clone()); // closePolygon - } - - } else { - throw new Error('unknown command ' + cmd); - } - } - - if (line) lines.push(line); - - return lines; -}; - -VectorTileFeature.prototype.bbox = function() { - var pbf = this._pbf; - pbf.pos = this._geometry; - - var end = pbf.readVarint() + pbf.pos, - cmd = 1, - length = 0, - x = 0, - y = 0, - x1 = Infinity, - x2 = -Infinity, - y1 = Infinity, - y2 = -Infinity; - - while (pbf.pos < end) { - if (!length) { - var cmdLen = pbf.readVarint(); - cmd = cmdLen & 0x7; - length = cmdLen >> 3; - } - - length--; - - if (cmd === 1 || cmd === 2) { - x += pbf.readSVarint(); - y += pbf.readSVarint(); - if (x < x1) x1 = x; - if (x > x2) x2 = x; - if (y < y1) y1 = y; - if (y > y2) y2 = y; - - } else if (cmd !== 7) { - throw new Error('unknown command ' + cmd); - } - } - - return [x1, y1, x2, y2]; -}; - -VectorTileFeature.prototype.toGeoJSON = function(x, y, z) { - var size = this.extent * Math.pow(2, z), - x0 = this.extent * x, - y0 = this.extent * y, - coords = this.loadGeometry(), - type = VectorTileFeature.types[this.type]; - - for (var i = 0; i < coords.length; i++) { - var line = coords[i]; - for (var j = 0; j < line.length; j++) { - var p = line[j], y2 = 180 - (p.y + y0) * 360 / size; - line[j] = [ - (p.x + x0) * 360 / size - 180, - 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90 - ]; - } - } - - if (type === 'Point' && coords.length === 1) { - coords = coords[0][0]; - } else if (type === 'Point') { - coords = coords[0]; - type = 'MultiPoint'; - } else if (type === 'LineString' && coords.length === 1) { - coords = coords[0]; - } else if (type === 'LineString') { - type = 'MultiLineString'; - } - - var result = { - type: "Feature", - geometry: { - type: type, - coordinates: coords - }, - properties: this.properties - }; - - if ('_id' in this) { - result.id = this._id; - } - - return result; -}; - -},{"point-geometry":162}],171:[function(require,module,exports){ -'use strict'; - -var VectorTileFeature = require('./vectortilefeature.js'); - -module.exports = VectorTileLayer; - -function VectorTileLayer(pbf, end) { - // Public - this.version = 1; - this.name = null; - this.extent = 4096; - this.length = 0; - - // Private - this._pbf = pbf; - this._keys = []; - this._values = []; - this._features = []; - - pbf.readFields(readLayer, this, end); - - this.length = this._features.length; -} - -function readLayer(tag, layer, pbf) { - if (tag === 15) layer.version = pbf.readVarint(); - else if (tag === 1) layer.name = pbf.readString(); - else if (tag === 5) layer.extent = pbf.readVarint(); - else if (tag === 2) layer._features.push(pbf.pos); - else if (tag === 3) layer._keys.push(pbf.readString()); - else if (tag === 4) layer._values.push(readValueMessage(pbf)); -} - -function readValueMessage(pbf) { - var value = null, - end = pbf.readVarint() + pbf.pos; - - while (pbf.pos < end) { - var tag = pbf.readVarint() >> 3; - - value = tag === 1 ? pbf.readString() : - tag === 2 ? pbf.readFloat() : - tag === 3 ? pbf.readDouble() : - tag === 4 ? pbf.readVarint64() : - tag === 5 ? pbf.readVarint() : - tag === 6 ? pbf.readSVarint() : - tag === 7 ? pbf.readBoolean() : null; - } - - return value; + while (pbf.pos < end) { + var key = feature._keys[pbf.readVarint()], + value = feature._values[pbf.readVarint()]; + feature.properties[key] = value; + } } -// return feature `i` from this layer as a `VectorTileFeature` -VectorTileLayer.prototype.feature = function(i) { - if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds'); +VectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon']; - this._pbf.pos = this._features[i]; +VectorTileFeature.prototype.loadGeometry = function() { + var pbf = this._pbf; + pbf.pos = this._geometry; - var end = this._pbf.readVarint() + this._pbf.pos; - return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values); -}; + var end = pbf.readVarint() + pbf.pos, + cmd = 1, + length = 0, + x = 0, + y = 0, + lines = [], + line; -},{"./vectortilefeature.js":170}],172:[function(require,module,exports){ -var bundleFn = arguments[3]; -var sources = arguments[4]; -var cache = arguments[5]; + while (pbf.pos < end) { + if (!length) { + var cmdLen = pbf.readVarint(); + cmd = cmdLen & 0x7; + length = cmdLen >> 3; + } -var stringify = JSON.stringify; + length--; -module.exports = function (fn) { - var keys = []; - var wkey; - var cacheKeys = Object.keys(cache); + if (cmd === 1 || cmd === 2) { + x += pbf.readSVarint(); + y += pbf.readSVarint(); - for (var i = 0, l = cacheKeys.length; i < l; i++) { - var key = cacheKeys[i]; - var exp = cache[key].exports; - // Using babel as a transpiler to use esmodule, the export will always - // be an object with the default export as a property of it. To ensure - // the existing api and babel esmodule exports are both supported we - // check for both - if (exp === fn || exp.default === fn) { - wkey = key; - break; - } - } + if (cmd === 1) { // moveTo + if (line) lines.push(line); + line = []; + } - if (!wkey) { - wkey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16); - var wcache = {}; - for (var i = 0, l = cacheKeys.length; i < l; i++) { - var key = cacheKeys[i]; - wcache[key] = key; - } - sources[wkey] = [ - Function(['require','module','exports'], '(' + fn + ')(self)'), - wcache - ]; - } - var skey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16); + line.push(new Point(x, y)); - var scache = {}; scache[wkey] = wkey; - sources[skey] = [ - Function(['require'], ( - // try to call default if defined to also support babel esmodule - // exports - 'var f = require(' + stringify(wkey) + ');' + - '(f.default ? f.default : f)(self);' - )), - scache - ]; + } else if (cmd === 7) { - var src = '(' + bundleFn + ')({' - + Object.keys(sources).map(function (key) { - return stringify(key) + ':[' - + sources[key][0] - + ',' + stringify(sources[key][1]) + ']' - ; - }).join(',') - + '},{},[' + stringify(skey) + '])' - ; + // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90 + if (line) { + line.push(line[0].clone()); // closePolygon + } - var URL = window.URL || window.webkitURL || window.mozURL || window.msURL; + } else { + throw new Error('unknown command ' + cmd); + } + } + + if (line) lines.push(line); - return new Worker(URL.createObjectURL( - new Blob([src], { type: 'text/javascript' }) - )); + return lines; }; -},{}],173:[function(require,module,exports){ -// 1. run tin on points -// 2. calculate lenth of all edges and area of all triangles -// 3. remove triangles that fail the max length test -// 4. buffer the results slightly -// 5. merge the results -var t = {}; -t.tin = require('turf-tin'); -t.merge = require('turf-merge'); -t.distance = require('turf-distance'); -t.point = require('turf-point'); +VectorTileFeature.prototype.bbox = function() { + var pbf = this._pbf; + pbf.pos = this._geometry; -/** - * Takes a {@link FeatureCollection} of {@link Point} features and - * returns a concave hull. - * - * Internally, this implements - * a [Monotone chain algorithm](http://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#JavaScript). - * - * @module turf/concave - * @category transformation - * @param {FeatureCollection} points a FeatureCollection of {@link Point} features - * @param {number} maxEdge the size of an edge necessary for part of the - * hull to become concave (in miles) - * @param {String} units used for maxEdge distance (miles or kilometers) - * @returns {Feature} a {@link Polygon} feature - * @throws {Error} if maxEdge parameter is missing - * @example - * var points = { - * "type": "FeatureCollection", - * "features": [ - * { - * "type": "Feature", - * "properties": {}, - * "geometry": { - * "type": "Point", - * "coordinates": [-63.601226, 44.642643] - * } - * }, { - * "type": "Feature", - * "properties": {}, - * "geometry": { - * "type": "Point", - * "coordinates": [-63.591442, 44.651436] - * } - * }, { - * "type": "Feature", - * "properties": {}, - * "geometry": { - * "type": "Point", - * "coordinates": [-63.580799, 44.648749] - * } - * }, { - * "type": "Feature", - * "properties": {}, - * "geometry": { - * "type": "Point", - * "coordinates": [-63.573589, 44.641788] - * } - * }, { - * "type": "Feature", - * "properties": {}, - * "geometry": { - * "type": "Point", - * "coordinates": [-63.587665, 44.64533] - * } - * }, { - * "type": "Feature", - * "properties": {}, - * "geometry": { - * "type": "Point", - * "coordinates": [-63.595218, 44.64765] - * } - * } - * ] - * }; - * - * var hull = turf.concave(points, 1, 'miles'); - * - * var resultFeatures = points.features.concat(hull); - * var result = { - * "type": "FeatureCollection", - * "features": resultFeatures - * }; - * - * //=result - */ + var end = pbf.readVarint() + pbf.pos, + cmd = 1, + length = 0, + x = 0, + y = 0, + x1 = Infinity, + x2 = -Infinity, + y1 = Infinity, + y2 = -Infinity; + while (pbf.pos < end) { + if (!length) { + var cmdLen = pbf.readVarint(); + cmd = cmdLen & 0x7; + length = cmdLen >> 3; + } -module.exports = function(points, maxEdge, units) { - if (typeof maxEdge !== 'number') throw new Error('maxEdge parameter is required'); - if (typeof units !== 'string') throw new Error('units parameter is required'); + length--; - var tinPolys = t.tin(points); - var filteredPolys = tinPolys.features.filter(filterTriangles); - tinPolys.features = filteredPolys; + if (cmd === 1 || cmd === 2) { + x += pbf.readSVarint(); + y += pbf.readSVarint(); + if (x < x1) x1 = x; + if (x > x2) x2 = x; + if (y < y1) y1 = y; + if (y > y2) y2 = y; - function filterTriangles(triangle) { - var pt1 = t.point(triangle.geometry.coordinates[0][0]); - var pt2 = t.point(triangle.geometry.coordinates[0][1]); - var pt3 = t.point(triangle.geometry.coordinates[0][2]); - var dist1 = t.distance(pt1, pt2, units); - var dist2 = t.distance(pt2, pt3, units); - var dist3 = t.distance(pt1, pt3, units); - return (dist1 <= maxEdge && dist2 <= maxEdge && dist3 <= maxEdge); - } + } else if (cmd !== 7) { + throw new Error('unknown command ' + cmd); + } + } - return t.merge(tinPolys); + return [x1, y1, x2, y2]; }; -},{"turf-distance":174,"turf-merge":176,"turf-point":183,"turf-tin":184}],174:[function(require,module,exports){ -var invariant = require('turf-invariant'); -//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 degress, radians, - * miles, or kilometers. This uses the - * [Haversine formula](http://en.wikipedia.org/wiki/Haversine_formula) - * to account for global curvature. - * - * @module turf/distance - * @category measurement - * @param {Feature} from origin point - * @param {Feature} to destination point - * @param {String} [units=kilometers] can be degrees, radians, miles, or kilometers - * @return {Number} distance between the two points - * @example - * var point1 = { - * "type": "Feature", - * "properties": {}, - * "geometry": { - * "type": "Point", - * "coordinates": [-75.343, 39.984] - * } - * }; - * var point2 = { - * "type": "Feature", - * "properties": {}, - * "geometry": { - * "type": "Point", - * "coordinates": [-75.534, 39.123] - * } - * }; - * var units = "miles"; - * - * var points = { - * "type": "FeatureCollection", - * "features": [point1, point2] - * }; - * - * //=points - * - * var distance = turf.distance(point1, point2, units); - * - * //=distance - */ -module.exports = function(point1, point2, units) { - invariant.featureOf(point1, 'Point', 'distance'); - invariant.featureOf(point2, 'Point', 'distance'); - var coordinates1 = point1.geometry.coordinates; - var coordinates2 = point2.geometry.coordinates; - - var dLat = toRad(coordinates2[1] - coordinates1[1]); - var dLon = toRad(coordinates2[0] - coordinates1[0]); - var lat1 = toRad(coordinates1[1]); - var lat2 = toRad(coordinates2[1]); - - var a = Math.pow(Math.sin(dLat/2), 2) + - Math.pow(Math.sin(dLon/2), 2) * Math.cos(lat1) * Math.cos(lat2); - var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); - - var R; - switch(units) { - case 'miles': - R = 3960; - break; - case 'kilometers': - case 'kilometres': - R = 6373; - break; - case 'degrees': - R = 57.2957795; - break; - case 'radians': - R = 1; - break; - case undefined: - R = 6373; - break; - default: - throw new Error('unknown option given to "units"'); - } - - var distance = R * c; - return distance; -}; +VectorTileFeature.prototype.toGeoJSON = function(x, y, z) { + var size = this.extent * Math.pow(2, z), + x0 = this.extent * x, + y0 = this.extent * y, + coords = this.loadGeometry(), + type = VectorTileFeature.types[this.type], + i, j; -function toRad(degree) { - return degree * Math.PI / 180; -} + function project(line) { + for (var j = 0; j < line.length; j++) { + var p = line[j], y2 = 180 - (p.y + y0) * 360 / size; + line[j] = [ + (p.x + x0) * 360 / size - 180, + 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90 + ]; + } + } -},{"turf-invariant":175}],175:[function(require,module,exports){ -module.exports.geojsonType = geojsonType; -module.exports.collectionOf = collectionOf; -module.exports.featureOf = featureOf; + switch (this.type) { + case 1: + var points = []; + for (i = 0; i < coords.length; i++) { + points[i] = coords[i][0]; + } + coords = points; + project(coords); + break; -/** - * Enforce expectations about types of GeoJSON objects for Turf. - * - * @alias 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'); + case 2: + for (i = 0; i < coords.length; i++) { + project(coords[i]); + } + break; - if (!value || value.type !== type) { - throw new Error('Invalid input to ' + name + ': must be a ' + type + ', given ' + value.type); + case 3: + coords = classifyRings(coords); + for (i = 0; i < coords.length; i++) { + for (j = 0; j < coords[i].length; j++) { + project(coords[i][j]); + } + } + break; } -} -/** - * Enforce expectations about types of {@link Feature} inputs for Turf. - * Internally this uses {@link geojsonType} to judge geometry types. - * - * @alias 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 if value is not the expected type. - */ -function featureOf(value, type, name) { - if (!name) throw new Error('.featureOf() requires a name'); - if (!value || value.type !== 'Feature' || !value.geometry) { - throw new Error('Invalid input to ' + name + ', Feature with geometry required'); - } - if (!value.geometry || value.geometry.type !== type) { - throw new Error('Invalid input to ' + name + ': must be a ' + type + ', given ' + value.geometry.type); + if (coords.length === 1) { + coords = coords[0]; + } else { + type = 'Multi' + type; } -} -/** - * Enforce expectations about types of {@link FeatureCollection} inputs for Turf. - * Internally this uses {@link geojsonType} to judge geometry types. - * - * @alias 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(value, type, name) { - if (!name) throw new Error('.collectionOf() requires a name'); - if (!value || value.type !== 'FeatureCollection') { - throw new Error('Invalid input to ' + name + ', FeatureCollection required'); - } - for (var i = 0; i < value.features.length; i++) { - var feature = value.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); - } + var result = { + type: "Feature", + geometry: { + type: type, + coordinates: coords + }, + properties: this.properties + }; + + if ('id' in this) { + result.id = this.id; } -} -},{}],176:[function(require,module,exports){ -var clone = require('clone'); -var union = require('turf-union'); + return result; +}; -/** - * Takes a {@link FeatureCollection} of {@link Polygon} features and returns a single merged - * polygon feature. If the input Polygon features are not contiguous, this function returns a {@link MultiPolygon} feature. - * @module turf/merge - * @category transformation - * @param {FeatureCollection} fc a FeatureCollection of {@link Polygon} features - * @return {Feature} a {@link Polygon} or {@link MultiPolygon} feature - * @example - * var polygons = { - * "type": "FeatureCollection", - * "features": [ - * { - * "type": "Feature", - * "properties": { - * "fill": "#0f0" - * }, - * "geometry": { - * "type": "Polygon", - * "coordinates": [[ - * [9.994812, 53.549487], - * [10.046997, 53.598209], - * [10.117721, 53.531737], - * [9.994812, 53.549487] - * ]] - * } - * }, { - * "type": "Feature", - * "properties": { - * "fill": "#00f" - * }, - * "geometry": { - * "type": "Polygon", - * "coordinates": [[ - * [10.000991, 53.50418], - * [10.03807, 53.562539], - * [9.926834, 53.551731], - * [10.000991, 53.50418] - * ]] - * } - * } - * ] - * }; - * - * var merged = turf.merge(polygons); - * - * //=polygons - * - * //=merged - */ -module.exports = function(polygons, done){ +// classifies an array of rings into polygons with outer rings and holes - var merged = clone(polygons.features[0]), - features = polygons.features; +function classifyRings(rings) { + var len = rings.length; - for (var i = 0, len = features.length; i < len; i++) { - var poly = features[i]; + if (len <= 1) return [rings]; - if(poly.geometry){ - merged = union(merged, poly); - } - } + var polygons = [], + polygon, + ccw; - return merged; -}; + for (var i = 0; i < len; i++) { + var area = signedArea(rings[i]); + if (area === 0) continue; -},{"clone":177,"turf-union":178}],177:[function(require,module,exports){ -(function (Buffer){ -'use strict'; + if (ccw === undefined) ccw = area < 0; -function objectToString(o) { - return Object.prototype.toString.call(o); + if (ccw === area < 0) { + if (polygon) polygons.push(polygon); + polygon = [rings[i]]; + + } else { + polygon.push(rings[i]); + } + } + if (polygon) polygons.push(polygon); + + return polygons; } -// shim for Node's 'util' package -// DO NOT REMOVE THIS! It is required for compatibility with EnderJS (http://enderjs.com/). -var util = { - isArray: function (ar) { - return Array.isArray(ar) || (typeof ar === 'object' && objectToString(ar) === '[object Array]'); - }, - isDate: function (d) { - return typeof d === 'object' && objectToString(d) === '[object Date]'; - }, - isRegExp: function (re) { - return typeof re === 'object' && objectToString(re) === '[object RegExp]'; - }, - getRegExpFlags: function (re) { - var flags = ''; - re.global && (flags += 'g'); - re.ignoreCase && (flags += 'i'); - re.multiline && (flags += 'm'); - return flags; - } -}; +function signedArea(ring) { + var sum = 0; + for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) { + p1 = ring[i]; + p2 = ring[j]; + sum += (p2.x - p1.x) * (p1.y + p2.y); + } + return sum; +} + +},{"point-geometry":196}],215:[function(require,module,exports){ +'use strict'; +var VectorTileFeature = require('./vectortilefeature.js'); -if (typeof module === 'object') - module.exports = clone; +module.exports = VectorTileLayer; -/** - * Clones (copies) an Object using deep copying. - * - * This function supports circular references by default, but if you are certain - * there are no circular references in your object, you can save some CPU time - * by calling clone(obj, false). - * - * Caution: if `circular` is false and `parent` contains circular references, - * your program may enter an infinite loop and crash. - * - * @param `parent` - the object to be cloned - * @param `circular` - set to true if the object to be cloned may contain - * circular references. (optional - true by default) - * @param `depth` - set to a number if the object is only to be cloned to - * a particular depth. (optional - defaults to Infinity) - * @param `prototype` - sets the prototype to be used when cloning an object. - * (optional - defaults to parent prototype). -*/ +function VectorTileLayer(pbf, end) { + // Public + this.version = 1; + this.name = null; + this.extent = 4096; + this.length = 0; + + // Private + this._pbf = pbf; + this._keys = []; + this._values = []; + this._features = []; -function clone(parent, circular, depth, prototype) { - // maintain two arrays for circular references, where corresponding parents - // and children have the same index - var allParents = []; - var allChildren = []; + pbf.readFields(readLayer, this, end); - var useBuffer = typeof Buffer != 'undefined'; + this.length = this._features.length; +} - if (typeof circular == 'undefined') - circular = true; +function readLayer(tag, layer, pbf) { + if (tag === 15) layer.version = pbf.readVarint(); + else if (tag === 1) layer.name = pbf.readString(); + else if (tag === 5) layer.extent = pbf.readVarint(); + else if (tag === 2) layer._features.push(pbf.pos); + else if (tag === 3) layer._keys.push(pbf.readString()); + else if (tag === 4) layer._values.push(readValueMessage(pbf)); +} - if (typeof depth == 'undefined') - depth = Infinity; +function readValueMessage(pbf) { + var value = null, + end = pbf.readVarint() + pbf.pos; - // recurse this function so we don't reset allParents and allChildren - function _clone(parent, depth) { - // cloning null always returns null - if (parent === null) - return null; + while (pbf.pos < end) { + var tag = pbf.readVarint() >> 3; - if (depth == 0) - return parent; - - var child; - var proto; - if (typeof parent != 'object') { - return parent; - } - - if (util.isArray(parent)) { - child = []; - } else if (util.isRegExp(parent)) { - child = new RegExp(parent.source, util.getRegExpFlags(parent)); - if (parent.lastIndex) child.lastIndex = parent.lastIndex; - } else if (util.isDate(parent)) { - child = new Date(parent.getTime()); - } else if (useBuffer && Buffer.isBuffer(parent)) { - child = new Buffer(parent.length); - parent.copy(child); - return child; - } else { - if (typeof prototype == 'undefined') { - proto = Object.getPrototypeOf(parent); - child = Object.create(proto); - } - else { - child = Object.create(prototype); - proto = prototype; - } + value = tag === 1 ? pbf.readString() : + tag === 2 ? pbf.readFloat() : + tag === 3 ? pbf.readDouble() : + tag === 4 ? pbf.readVarint64() : + tag === 5 ? pbf.readVarint() : + tag === 6 ? pbf.readSVarint() : + tag === 7 ? pbf.readBoolean() : null; } - if (circular) { - var index = allParents.indexOf(parent); + return value; +} - if (index != -1) { - return allChildren[index]; - } - allParents.push(parent); - allChildren.push(child); - } +// return feature `i` from this layer as a `VectorTileFeature` +VectorTileLayer.prototype.feature = function(i) { + if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds'); - for (var i in parent) { - var attrs; - if (proto) { - attrs = Object.getOwnPropertyDescriptor(proto, i); - } - - if (attrs && attrs.set == null) { - continue; - } - child[i] = _clone(parent[i], depth - 1); - } + this._pbf.pos = this._features[i]; + + var end = this._pbf.readVarint() + this._pbf.pos; + return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values); +}; + +},{"./vectortilefeature.js":214}],216:[function(require,module,exports){ +var Pbf = require('pbf') +var vtpb = require('./vector-tile-pb') +var GeoJSONWrapper = require('./lib/geojson_wrapper') + +module.exports = fromVectorTileJs +module.exports.fromVectorTileJs = fromVectorTileJs +module.exports.fromGeojsonVt = fromGeojsonVt +module.exports.GeoJSONWrapper = GeoJSONWrapper - return child; +/** + * Serialize a vector-tile-js-created tile to pbf + * + * @param {Object} tile + * @return {Buffer} uncompressed, pbf-serialized tile data + */ +function fromVectorTileJs (tile) { + var layers = [] + for (var l in tile.layers) { + layers.push(prepareLayer(tile.layers[l])) } - return _clone(parent, depth); + var out = new Pbf() + vtpb.tile.write({ layers: layers }, out) + return out.finish() } /** - * Simple flat clone using prototype, accepts only objects, usefull for property - * override on FLAT configuration object (no nested props). + * Serialized a geojson-vt-created tile to pbf. * - * USE WITH CAUTION! This may not behave as you wish if you do not know how this - * works. + * @param {Object} layers - An object mapping layer names to geojson-vt-created vector tile objects + * @return {Buffer} uncompressed, pbf-serialized tile data */ -clone.clonePrototype = function(parent) { - if (parent === null) - return null; +function fromGeojsonVt (layers) { + var l = {} + for (var k in layers) { + l[k] = new GeoJSONWrapper(layers[k].features) + l[k].name = k + } + return fromVectorTileJs({layers: l}) +} - var c = function () {}; - c.prototype = parent; - return new c(); -}; +/** + * Prepare the given layer to be serialized by the auto-generated pbf + * serializer by encoding the feature geometry and properties. + */ +function prepareLayer (layer) { + var preparedLayer = { + name: layer.name || '', + version: layer.version || 1, + extent: layer.extent || 4096, + keys: [], + values: [], + features: [] + } -}).call(this,require("buffer").Buffer) -},{"buffer":3}],178:[function(require,module,exports){ -// look here for help http://svn.osgeo.org/grass/grass/branches/releasebranch_6_4/vector/v.overlay/main.c -//must be array of polygons + var keycache = {} + var valuecache = {} -// depend on jsts for now https://github.com/bjornharrtell/jsts/blob/master/examples/overlay.html + for (var i = 0; i < layer.length; i++) { + var feature = layer.feature(i) + feature.geometry = encodeGeometry(feature.loadGeometry()) -var jsts = require('jsts'); + var tags = [] + for (var key in feature.properties) { + var keyIndex = keycache[key] + if (typeof keyIndex === 'undefined') { + preparedLayer.keys.push(key) + keyIndex = preparedLayer.keys.length - 1 + keycache[key] = keyIndex + } + var value = wrapValue(feature.properties[key]) + var valueIndex = valuecache[value.key] + if (typeof valueIndex === 'undefined') { + preparedLayer.values.push(value) + valueIndex = preparedLayer.values.length - 1 + valuecache[value.key] = valueIndex + } + tags.push(keyIndex) + tags.push(valueIndex) + } -/** - * Takes two {@link Polygon|polygons} and returns a combined polygon. If the input polygons are not contiguous, this function returns a {@link MultiPolygon} feature. - * - * @module turf/union - * @category transformation - * @param {Feature} poly1 input polygon - * @param {Feature} poly2 another input polygon - * @return {Feature<(Polygon|MultiPolygon)>} a combined {@link Polygon} or {@link MultiPolygon} feature - * @example - * var poly1 = { - * "type": "Feature", - * "properties": { - * "fill": "#0f0" - * }, - * "geometry": { - * "type": "Polygon", - * "coordinates": [[ - * [-82.574787, 35.594087], - * [-82.574787, 35.615581], - * [-82.545261, 35.615581], - * [-82.545261, 35.594087], - * [-82.574787, 35.594087] - * ]] - * } - * }; - * var poly2 = { - * "type": "Feature", - * "properties": { - * "fill": "#00f" - * }, - * "geometry": { - * "type": "Polygon", - * "coordinates": [[ - * [-82.560024, 35.585153], - * [-82.560024, 35.602602], - * [-82.52964, 35.602602], - * [-82.52964, 35.585153], - * [-82.560024, 35.585153] - * ]] - * } - * }; - * var polygons = { - * "type": "FeatureCollection", - * "features": [poly1, poly2] - * }; - * - * var union = turf.union(poly1, poly2); - * - * //=polygons - * - * //=union - */ -module.exports = function(poly1, poly2){ - var reader = new jsts.io.GeoJSONReader(); - var a = reader.read(JSON.stringify(poly1.geometry)); - var b = reader.read(JSON.stringify(poly2.geometry)); - var union = a.union(b); - var parser = new jsts.io.GeoJSONParser(); + feature.tags = tags + preparedLayer.features.push(feature) + } - union = parser.write(union); - return { - type: 'Feature', - geometry: union, - properties: poly1.properties - }; + return preparedLayer } -},{"jsts":179}],179:[function(require,module,exports){ -require('javascript.util'); -var jsts = require('./lib/jsts'); -module.exports = jsts - -},{"./lib/jsts":180,"javascript.util":182}],180:[function(require,module,exports){ -/* The JSTS Topology Suite is a collection of JavaScript classes that -implement the fundamental operations required to validate a given -geo-spatial data set to a known topological specification. - -Copyright (C) 2011 The Authors - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -jsts={version:'0.15.0',algorithm:{distance:{},locate:{}},error:{},geom:{util:{}},geomgraph:{index:{}},index:{bintree:{},chain:{},kdtree:{},quadtree:{},strtree:{}},io:{},noding:{snapround:{}},operation:{buffer:{},distance:{},overlay:{snap:{}},polygonize:{},predicate:{},relate:{},union:{},valid:{}},planargraph:{},simplify:{},triangulate:{quadedge:{}},util:{}};if(typeof String.prototype.trim!=='function'){String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,'');};} -jsts.abstractFunc=function(){throw new jsts.error.AbstractMethodInvocationError();};jsts.error={};jsts.error.IllegalArgumentError=function(message){this.name='IllegalArgumentError';this.message=message;};jsts.error.IllegalArgumentError.prototype=new Error();jsts.error.TopologyError=function(message,pt){this.name='TopologyError';this.message=pt?message+' [ '+pt+' ]':message;};jsts.error.TopologyError.prototype=new Error();jsts.error.AbstractMethodInvocationError=function(){this.name='AbstractMethodInvocationError';this.message='Abstract method called, should be implemented in subclass.';};jsts.error.AbstractMethodInvocationError.prototype=new Error();jsts.error.NotImplementedError=function(){this.name='NotImplementedError';this.message='This method has not yet been implemented.';};jsts.error.NotImplementedError.prototype=new Error();jsts.error.NotRepresentableError=function(message){this.name='NotRepresentableError';this.message=message;};jsts.error.NotRepresentableError.prototype=new Error();jsts.error.LocateFailureError=function(message){this.name='LocateFailureError';this.message=message;};jsts.error.LocateFailureError.prototype=new Error();if(typeof module!=="undefined")module.exports=jsts;jsts.geom.GeometryFilter=function(){};jsts.geom.GeometryFilter.prototype.filter=function(geom){throw new jsts.error.AbstractMethodInvocationError();};jsts.geom.util.PolygonExtracter=function(comps){this.comps=comps;};jsts.geom.util.PolygonExtracter.prototype=new jsts.geom.GeometryFilter();jsts.geom.util.PolygonExtracter.prototype.comps=null;jsts.geom.util.PolygonExtracter.getPolygons=function(geom,list){if(list===undefined){list=[];} -if(geom instanceof jsts.geom.Polygon){list.push(geom);}else if(geom instanceof jsts.geom.GeometryCollection){geom.apply(new jsts.geom.util.PolygonExtracter(list));} -return list;};jsts.geom.util.PolygonExtracter.prototype.filter=function(geom){if(geom instanceof jsts.geom.Polygon) -this.comps.push(geom);};jsts.io.WKTParser=function(geometryFactory){this.geometryFactory=geometryFactory||new jsts.geom.GeometryFactory();this.regExes={'typeStr':/^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/,'emptyTypeStr':/^\s*(\w+)\s*EMPTY\s*$/,'spaces':/\s+/,'parenComma':/\)\s*,\s*\(/,'doubleParenComma':/\)\s*\)\s*,\s*\(\s*\(/,'trimParens':/^\s*\(?(.*?)\)?\s*$/};};jsts.io.WKTParser.prototype.read=function(wkt){var geometry,type,str;wkt=wkt.replace(/[\n\r]/g,' ');var matches=this.regExes.typeStr.exec(wkt);if(wkt.search('EMPTY')!==-1){matches=this.regExes.emptyTypeStr.exec(wkt);matches[2]=undefined;} -if(matches){type=matches[1].toLowerCase();str=matches[2];if(this.parse[type]){geometry=this.parse[type].apply(this,[str]);}} -if(geometry===undefined) -throw new Error('Could not parse WKT '+wkt);return geometry;};jsts.io.WKTParser.prototype.write=function(geometry){return this.extractGeometry(geometry);};jsts.io.WKTParser.prototype.extractGeometry=function(geometry){var type=geometry.CLASS_NAME.split('.')[2].toLowerCase();if(!this.extract[type]){return null;} -var wktType=type.toUpperCase();var data;if(geometry.isEmpty()){data=wktType+' EMPTY';}else{data=wktType+'('+this.extract[type].apply(this,[geometry])+')';} -return data;};jsts.io.WKTParser.prototype.extract={'coordinate':function(coordinate){return coordinate.x+' '+coordinate.y;},'point':function(point){return point.coordinate.x+' '+point.coordinate.y;},'multipoint':function(multipoint){var array=[];for(var i=0,len=multipoint.geometries.length;ihiPt.y){hiPt=p;hiIndex=i;}} -iPrev=hiIndex;do{iPrev=iPrev-1;if(iPrev<0){iPrev=nPts;}}while(ring[iPrev].equals2D(hiPt)&&iPrev!==hiIndex);iNext=hiIndex;do{iNext=(iNext+1)%nPts;}while(ring[iNext].equals2D(hiPt)&&iNext!==hiIndex);prev=ring[iPrev];next=ring[iNext];if(prev.equals2D(hiPt)||next.equals2D(hiPt)||prev.equals2D(next)){return false;} -disc=jsts.algorithm.CGAlgorithms.computeOrientation(prev,hiPt,next);isCCW=false;if(disc===0){isCCW=(prev.x>next.x);}else{isCCW=(disc>0);} -return isCCW;};jsts.algorithm.CGAlgorithms.computeOrientation=function(p1,p2,q){return jsts.algorithm.CGAlgorithms.orientationIndex(p1,p2,q);};jsts.algorithm.CGAlgorithms.distancePointLine=function(p,A,B){if(!(A instanceof jsts.geom.Coordinate)){jsts.algorithm.CGAlgorithms.distancePointLine2.apply(this,arguments);} -if(A.x===B.x&&A.y===B.y){return p.distance(A);} -var r,s;r=((p.x-A.x)*(B.x-A.x)+(p.y-A.y)*(B.y-A.y))/((B.x-A.x)*(B.x-A.x)+(B.y-A.y)*(B.y-A.y));if(r<=0.0){return p.distance(A);} -if(r>=1.0){return p.distance(B);} -s=((A.y-p.y)*(B.x-A.x)-(A.x-p.x)*(B.y-A.y))/((B.x-A.x)*(B.x-A.x)+(B.y-A.y)*(B.y-A.y));return Math.abs(s)*Math.sqrt(((B.x-A.x)*(B.x-A.x)+(B.y-A.y)*(B.y-A.y)));};jsts.algorithm.CGAlgorithms.distancePointLinePerpendicular=function(p,A,B){var s=((A.y-p.y)*(B.x-A.x)-(A.x-p.x)*(B.y-A.y))/((B.x-A.x)*(B.x-A.x)+(B.y-A.y)*(B.y-A.y));return Math.abs(s)*Math.sqrt(((B.x-A.x)*(B.x-A.x)+(B.y-A.y)*(B.y-A.y)));};jsts.algorithm.CGAlgorithms.distancePointLine2=function(p,line){var minDistance,i,il,dist;if(line.length===0){throw new jsts.error.IllegalArgumentError('Line array must contain at least one vertex');} -minDistance=p.distance(line[0]);for(i=0,il=line.length-1;i1)||(s<0)||(s>1)){return Math.min(jsts.algorithm.CGAlgorithms.distancePointLine(A,C,D),Math.min(jsts.algorithm.CGAlgorithms.distancePointLine(B,C,D),Math.min(jsts.algorithm.CGAlgorithms.distancePointLine(C,A,B),jsts.algorithm.CGAlgorithms.distancePointLine(D,A,B))));} -return 0.0;};jsts.algorithm.CGAlgorithms.signedArea=function(ring){if(ring.length<3){return 0.0;} -var sum,i,il,bx,by,cx,cy;sum=0.0;for(i=0,il=ring.length-1;i0;};jsts.algorithm.Angle.isObtuse=function(p0,p1,p2){var dx0,dy0,dx1,dy1,dotprod;dx0=p0.x-p1.x;dy0=p0.y-p1.y;dx1=p2.x-p1.x;dy1=p2.y-p1.y;dotprod=dx0*dx1+dy0*dy1;return dotprod<0;};jsts.algorithm.Angle.angleBetween=function(tip1,tail,tip2){var a1,a2;a1=jsts.algorithm.Angle.angle(tail,tip1);a2=jsts.algorithm.Angle.angle(tail,tip2);return jsts.algorithm.Angle.diff(a1,a2);};jsts.algorithm.Angle.angleBetweenOriented=function(tip1,tail,tip2){var a1,a2,angDel;a1=jsts.algorithm.Angle.angle(tail,tip1);a2=jsts.algorithm.Angle.angle(tail,tip2);angDel=a2-a1;if(angDel<=-Math.PI){return angDel+jsts.algorithm.Angle.PI_TIMES_2;} -if(angDel>Math.PI){return angDel-jsts.algorithm.Angle.PI_TIMES_2;} -return angDel;};jsts.algorithm.Angle.interiorAngle=function(p0,p1,p2){var anglePrev,angleNext;anglePrev=jsts.algorithm.Angle.angle(p1,p0);angleNext=jsts.algorithm.Angle.angle(p1,p2);return Math.abs(angleNext-anglePrev);};jsts.algorithm.Angle.getTurn=function(ang1,ang2){var crossproduct=Math.sin(ang2-ang1);if(crossproduct>0){return jsts.algorithm.Angle.COUNTERCLOCKWISE;} -if(crossproduct<0){return jsts.algorithm.Angle.CLOCKWISE;} -return jsts.algorithm.Angle.NONE;};jsts.algorithm.Angle.normalize=function(angle){while(angle>Math.PI){angle-=jsts.algorithm.Angle.PI_TIMES_2;} -while(angle<=-Math.PI){angle+=jsts.algorithm.Angle.PI_TIMES_2;} -return angle;};jsts.algorithm.Angle.normalizePositive=function(angle){if(angle<0.0){while(angle<0.0){angle+=jsts.algorithm.Angle.PI_TIMES_2;} -if(angle>=jsts.algorithm.Angle.PI_TIMES_2){angle=0.0;}} -else{while(angle>=jsts.algorithm.Angle.PI_TIMES_2){angle-=jsts.algorithm.Angle.PI_TIMES_2;} -if(angle<0.0){angle=0.0;}} -return angle;};jsts.algorithm.Angle.diff=function(ang1,ang2){var delAngle;if(ang1Math.PI){delAngle=(2*Math.PI)-delAngle;} -return delAngle;};jsts.geom.GeometryComponentFilter=function(){};jsts.geom.GeometryComponentFilter.prototype.filter=function(geom){throw new jsts.error.AbstractMethodInvocationError();};jsts.geom.util.LinearComponentExtracter=function(lines,isForcedToLineString){this.lines=lines;this.isForcedToLineString=isForcedToLineString;};jsts.geom.util.LinearComponentExtracter.prototype=new jsts.geom.GeometryComponentFilter();jsts.geom.util.LinearComponentExtracter.prototype.lines=null;jsts.geom.util.LinearComponentExtracter.prototype.isForcedToLineString=false;jsts.geom.util.LinearComponentExtracter.getLines=function(geoms,lines){if(arguments.length==1){return jsts.geom.util.LinearComponentExtracter.getLines5.apply(this,arguments);} -else if(arguments.length==2&&typeof lines==='boolean'){return jsts.geom.util.LinearComponentExtracter.getLines6.apply(this,arguments);} -else if(arguments.length==2&&geoms instanceof jsts.geom.Geometry){return jsts.geom.util.LinearComponentExtracter.getLines3.apply(this,arguments);} -else if(arguments.length==3&&geoms instanceof jsts.geom.Geometry){return jsts.geom.util.LinearComponentExtracter.getLines4.apply(this,arguments);} -else if(arguments.length==3){return jsts.geom.util.LinearComponentExtracter.getLines2.apply(this,arguments);} -for(var i=0;idistance){return false;} -return DistanceOp.isWithinDistance(this,geom,distance);};jsts.geom.Geometry.prototype.isRectangle=function(){return false;};jsts.geom.Geometry.prototype.getArea=function(){return 0.0;};jsts.geom.Geometry.prototype.getLength=function(){return 0.0;};jsts.geom.Geometry.prototype.getCentroid=function(){if(this.isEmpty()){return null;} -var cent;var centPt=null;var dim=this.getDimension();if(dim===0){cent=new jsts.algorithm.CentroidPoint();cent.add(this);centPt=cent.getCentroid();}else if(dim===1){cent=new jsts.algorithm.CentroidLine();cent.add(this);centPt=cent.getCentroid();}else{cent=new jsts.algorithm.CentroidArea();cent.add(this);centPt=cent.getCentroid();} -return this.createPointFromInternalCoord(centPt,this);};jsts.geom.Geometry.prototype.getInteriorPoint=function(){var intPt;var interiorPt=null;var dim=this.getDimension();if(dim===0){intPt=new jsts.algorithm.InteriorPointPoint(this);interiorPt=intPt.getInteriorPoint();}else if(dim===1){intPt=new jsts.algorithm.InteriorPointLine(this);interiorPt=intPt.getInteriorPoint();}else{intPt=new jsts.algorithm.InteriorPointArea(this);interiorPt=intPt.getInteriorPoint();} -return this.createPointFromInternalCoord(interiorPt,this);};jsts.geom.Geometry.prototype.getDimension=function(){throw new jsts.error.AbstractMethodInvocationError();};jsts.geom.Geometry.prototype.getBoundary=function(){throw new jsts.error.AbstractMethodInvocationError();};jsts.geom.Geometry.prototype.getBoundaryDimension=function(){throw new jsts.error.AbstractMethodInvocationError();};jsts.geom.Geometry.prototype.getEnvelope=function(){return this.getFactory().toGeometry(this.getEnvelopeInternal());};jsts.geom.Geometry.prototype.getEnvelopeInternal=function(){if(this.envelope===null){this.envelope=this.computeEnvelopeInternal();} -return this.envelope;};jsts.geom.Geometry.prototype.disjoint=function(g){return!this.intersects(g);};jsts.geom.Geometry.prototype.touches=function(g){if(!this.getEnvelopeInternal().intersects(g.getEnvelopeInternal())){return false;} -return this.relate(g).isTouches(this.getDimension(),g.getDimension());};jsts.geom.Geometry.prototype.intersects=function(g){if(!this.getEnvelopeInternal().intersects(g.getEnvelopeInternal())){return false;} -if(this.isRectangle()){return jsts.operation.predicate.RectangleIntersects.intersects(this,g);} -if(g.isRectangle()){return jsts.operation.predicate.RectangleIntersects.intersects(g,this);} -return this.relate(g).isIntersects();};jsts.geom.Geometry.prototype.crosses=function(g){if(!this.getEnvelopeInternal().intersects(g.getEnvelopeInternal())){return false;} -return this.relate(g).isCrosses(this.getDimension(),g.getDimension());};jsts.geom.Geometry.prototype.within=function(g){return g.contains(this);};jsts.geom.Geometry.prototype.contains=function(g){if(!this.getEnvelopeInternal().contains(g.getEnvelopeInternal())){return false;} -if(this.isRectangle()){return jsts.operation.predicate.RectangleContains.contains(this,g);} -return this.relate(g).isContains();};jsts.geom.Geometry.prototype.overlaps=function(g){if(!this.getEnvelopeInternal().intersects(g.getEnvelopeInternal())){return false;} -return this.relate(g).isOverlaps(this.getDimension(),g.getDimension());};jsts.geom.Geometry.prototype.covers=function(g){if(!this.getEnvelopeInternal().covers(g.getEnvelopeInternal())){return false;} -if(this.isRectangle()){return true;} -return this.relate(g).isCovers();};jsts.geom.Geometry.prototype.coveredBy=function(g){return g.covers(this);};jsts.geom.Geometry.prototype.relate=function(g,intersectionPattern){if(arguments.length===1){return this.relate2.apply(this,arguments);} -return this.relate2(g).matches(intersectionPattern);};jsts.geom.Geometry.prototype.relate2=function(g){this.checkNotGeometryCollection(this);this.checkNotGeometryCollection(g);return jsts.operation.relate.RelateOp.relate(this,g);};jsts.geom.Geometry.prototype.equalsTopo=function(g){if(!this.getEnvelopeInternal().equals(g.getEnvelopeInternal())){return false;} -return this.relate(g).isEquals(this.getDimension(),g.getDimension());};jsts.geom.Geometry.prototype.equals=function(o){if(o instanceof jsts.geom.Geometry||o instanceof jsts.geom.LinearRing||o instanceof jsts.geom.Polygon||o instanceof jsts.geom.GeometryCollection||o instanceof jsts.geom.MultiPoint||o instanceof jsts.geom.MultiLineString||o instanceof jsts.geom.MultiPolygon){return this.equalsExact(o);} -return false;};jsts.geom.Geometry.prototype.buffer=function(distance,quadrantSegments,endCapStyle){var params=new jsts.operation.buffer.BufferParameters(quadrantSegments,endCapStyle) -return jsts.operation.buffer.BufferOp.bufferOp2(this,distance,params);};jsts.geom.Geometry.prototype.convexHull=function(){return new jsts.algorithm.ConvexHull(this).getConvexHull();};jsts.geom.Geometry.prototype.intersection=function(other){if(this.isEmpty()){return this.getFactory().createGeometryCollection(null);} -if(other.isEmpty()){return this.getFactory().createGeometryCollection(null);} -if(this.isGeometryCollection(this)){var g2=other;} -this.checkNotGeometryCollection(this);this.checkNotGeometryCollection(other);return jsts.operation.overlay.snap.SnapIfNeededOverlayOp.overlayOp(this,other,jsts.operation.overlay.OverlayOp.INTERSECTION);};jsts.geom.Geometry.prototype.union=function(other){if(arguments.length===0){return jsts.operation.union.UnaryUnionOp.union(this);} -if(this.isEmpty()){return other.clone();} -if(other.isEmpty()){return this.clone();} -this.checkNotGeometryCollection(this);this.checkNotGeometryCollection(other);return jsts.operation.overlay.snap.SnapIfNeededOverlayOp.overlayOp(this,other,jsts.operation.overlay.OverlayOp.UNION);};jsts.geom.Geometry.prototype.difference=function(other){if(this.isEmpty()){return this.getFactory().createGeometryCollection(null);} -if(other.isEmpty()){return this.clone();} -this.checkNotGeometryCollection(this);this.checkNotGeometryCollection(other);return jsts.operation.overlay.snap.SnapIfNeededOverlayOp.overlayOp(this,other,jsts.operation.overlay.OverlayOp.DIFFERENCE);};jsts.geom.Geometry.prototype.symDifference=function(other){if(this.isEmpty()){return other.clone();} -if(other.isEmpty()){return this.clone();} -this.checkNotGeometryCollection(this);this.checkNotGeometryCollection(other);return jsts.operation.overlay.snap.SnapIfNeededOverlayOp.overlayOp(this,other,jsts.operation.overlay.OverlayOp.SYMDIFFERENCE);};jsts.geom.Geometry.prototype.equalsExact=function(other,tolerance){throw new jsts.error.AbstractMethodInvocationError();};jsts.geom.Geometry.prototype.equalsNorm=function(g){if(g===null||g===undefined) -return false;return this.norm().equalsExact(g.norm());};jsts.geom.Geometry.prototype.apply=function(filter){throw new jsts.error.AbstractMethodInvocationError();};jsts.geom.Geometry.prototype.clone=function(){throw new jsts.error.AbstractMethodInvocationError();};jsts.geom.Geometry.prototype.normalize=function(){throw new jsts.error.AbstractMethodInvocationError();};jsts.geom.Geometry.prototype.norm=function(){var copy=this.clone();copy.normalize();return copy;};jsts.geom.Geometry.prototype.compareTo=function(o){var other=o;if(this.getClassSortIndex()!==other.getClassSortIndex()){return this.getClassSortIndex()-other.getClassSortIndex();} -if(this.isEmpty()&&other.isEmpty()){return 0;} -if(this.isEmpty()){return-1;} -if(other.isEmpty()){return 1;} -return this.compareToSameClass(o);};jsts.geom.Geometry.prototype.isEquivalentClass=function(other){if(this instanceof jsts.geom.Point&&other instanceof jsts.geom.Point){return true;}else if(this instanceof jsts.geom.LineString&&(other instanceof jsts.geom.LineString|other instanceof jsts.geom.LinearRing)){return true;}else if(this instanceof jsts.geom.LinearRing&&(other instanceof jsts.geom.LineString|other instanceof jsts.geom.LinearRing)){return true;}else if(this instanceof jsts.geom.Polygon&&(other instanceof jsts.geom.Polygon)){return true;}else if(this instanceof jsts.geom.MultiPoint&&(other instanceof jsts.geom.MultiPoint)){return true;}else if(this instanceof jsts.geom.MultiLineString&&(other instanceof jsts.geom.MultiLineString)){return true;}else if(this instanceof jsts.geom.MultiPolygon&&(other instanceof jsts.geom.MultiPolygon)){return true;}else if(this instanceof jsts.geom.GeometryCollection&&(other instanceof jsts.geom.GeometryCollection)){return true;} -return false;};jsts.geom.Geometry.prototype.checkNotGeometryCollection=function(g){if(g.isGeometryCollectionBase()){throw new jsts.error.IllegalArgumentError('This method does not support GeometryCollection');}};jsts.geom.Geometry.prototype.isGeometryCollection=function(){return(this instanceof jsts.geom.GeometryCollection);};jsts.geom.Geometry.prototype.isGeometryCollectionBase=function(){return(this.CLASS_NAME==='jsts.geom.GeometryCollection');};jsts.geom.Geometry.prototype.computeEnvelopeInternal=function(){throw new jsts.error.AbstractMethodInvocationError();};jsts.geom.Geometry.prototype.compareToSameClass=function(o){throw new jsts.error.AbstractMethodInvocationError();};jsts.geom.Geometry.prototype.compare=function(a,b){var i=a.iterator();var j=b.iterator();while(i.hasNext()&&j.hasNext()){var aElement=i.next();var bElement=j.next();var comparison=aElement.compareTo(bElement);if(comparison!==0){return comparison;}} -if(i.hasNext()){return 1;} -if(j.hasNext()){return-1;} -return 0;};jsts.geom.Geometry.prototype.equal=function(a,b,tolerance){if(tolerance===undefined||tolerance===null||tolerance===0){return a.equals(b);} -return a.distance(b)<=tolerance;};jsts.geom.Geometry.prototype.getClassSortIndex=function(){var sortedClasses=[jsts.geom.Point,jsts.geom.MultiPoint,jsts.geom.LineString,jsts.geom.LinearRing,jsts.geom.MultiLineString,jsts.geom.Polygon,jsts.geom.MultiPolygon,jsts.geom.GeometryCollection];for(var i=0;iother.x){return 1;} -if(this.yother.y){return 1;} -return 0;};jsts.geom.Coordinate.prototype.toString=function(){return'('+this.x+', '+this.y+')';};})();jsts.geom.Envelope=function(){jsts.geom.Envelope.prototype.init.apply(this,arguments);};jsts.geom.Envelope.prototype.minx=null;jsts.geom.Envelope.prototype.maxx=null;jsts.geom.Envelope.prototype.miny=null;jsts.geom.Envelope.prototype.maxy=null;jsts.geom.Envelope.prototype.init=function(){if(typeof arguments[0]==='number'&&arguments.length===4){this.initFromValues(arguments[0],arguments[1],arguments[2],arguments[3]);}else if(arguments[0]instanceof jsts.geom.Coordinate&&arguments.length===1){this.initFromCoordinate(arguments[0]);}else if(arguments[0]instanceof jsts.geom.Coordinate&&arguments.length===2){this.initFromCoordinates(arguments[0],arguments[1]);}else if(arguments[0]instanceof jsts.geom.Envelope&&arguments.length===1){this.initFromEnvelope(arguments[0]);}else{this.setToNull();}};jsts.geom.Envelope.prototype.initFromValues=function(x1,x2,y1,y2){if(x1this.maxx){this.maxx=x;} -if(ythis.maxy){this.maxy=y;}}};jsts.geom.Envelope.prototype.expandToIncludeEnvelope=function(other){if(other.isNull()){return;} -if(this.isNull()){this.minx=other.getMinX();this.maxx=other.getMaxX();this.miny=other.getMinY();this.maxy=other.getMaxY();}else{if(other.minxthis.maxx){this.maxx=other.maxx;} -if(other.minythis.maxy){this.maxy=other.maxy;}}};jsts.geom.Envelope.prototype.expandBy=function(){if(arguments.length===1){this.expandByDistance(arguments[0]);}else{this.expandByDistances(arguments[0],arguments[1]);}};jsts.geom.Envelope.prototype.expandByDistance=function(distance){this.expandByDistances(distance,distance);};jsts.geom.Envelope.prototype.expandByDistances=function(deltaX,deltaY){if(this.isNull()){return;} -this.minx-=deltaX;this.maxx+=deltaX;this.miny-=deltaY;this.maxy+=deltaY;if(this.minx>this.maxx||this.miny>this.maxy){this.setToNull();}};jsts.geom.Envelope.prototype.translate=function(transX,transY){if(this.isNull()){return;} -this.init(this.minx+transX,this.maxx+transX,this.miny+transY,this.maxy+transY);};jsts.geom.Envelope.prototype.centre=function(){if(this.isNull()){return null;} -return new jsts.geom.Coordinate((this.minx+this.maxx)/2.0,(this.miny+this.maxy)/2.0);};jsts.geom.Envelope.prototype.intersection=function(env){if(this.isNull()||env.isNull()||!this.intersects(env)){return new jsts.geom.Envelope();} -var intMinX=this.minx>env.minx?this.minx:env.minx;var intMinY=this.miny>env.miny?this.miny:env.miny;var intMaxX=this.maxxthis.maxx||other.maxxthis.maxy||other.maxythis.maxx||xthis.maxy||y=this.minx&&x<=this.maxx&&y>=this.miny&&y<=this.maxy;};jsts.geom.Envelope.prototype.coversCoordinate=function(p){return this.coversValues(p.x,p.y);};jsts.geom.Envelope.prototype.coversEnvelope=function(other){if(this.isNull()||other.isNull()){return false;} -return other.minx>=this.minx&&other.maxx<=this.maxx&&other.miny>=this.miny&&other.maxy<=this.maxy;};jsts.geom.Envelope.prototype.distance=function(env){if(this.intersects(env)){return 0;} -var dx=0.0;if(this.maxxenv.maxx){dx=this.minx-env.maxx;} -var dy=0.0;if(this.maxyenv.maxy){dy=this.miny-env.maxy;} -if(dx===0.0){return dy;} -if(dy===0.0){return dx;} -return Math.sqrt(dx*dx+dy*dy);};jsts.geom.Envelope.prototype.equals=function(other){if(this.isNull()){return other.isNull();} -return this.maxx===other.maxx&&this.maxy===other.maxy&&this.minx===other.minx&&this.miny===other.miny;};jsts.geom.Envelope.prototype.toString=function(){return'Env['+this.minx+' : '+this.maxx+', '+this.miny+' : '+ -this.maxy+']';};jsts.geom.Envelope.intersects=function(p1,p2,q){if(arguments.length===4){return jsts.geom.Envelope.intersectsEnvelope(arguments[0],arguments[1],arguments[2],arguments[3]);} -var xc1=p1.xp2.x?p1.x:p2.x;var yc1=p1.yp2.y?p1.y:p2.y;if(((q.x>=xc1)&&(q.x<=xc2))&&((q.y>=yc1)&&(q.y<=yc2))){return true;} -return false;};jsts.geom.Envelope.intersectsEnvelope=function(p1,p2,q1,q2){var minq=Math.min(q1.x,q2.x);var maxq=Math.max(q1.x,q2.x);var minp=Math.min(p1.x,p2.x);var maxp=Math.max(p1.x,p2.x);if(minp>maxq){return false;} -if(maxpmaxq){return false;} -if(maxp1)return this.combine2.apply(this,arguments);var combiner=new jsts.geom.util.GeometryCombiner(geoms);return combiner.combine();};jsts.geom.util.GeometryCombiner.combine2=function(){var arrayList=new javascript.util.ArrayList();Array.prototype.slice.call(arguments).forEach(function(a){arrayList.add(a);});var combiner=new jsts.geom.util.GeometryCombiner(arrayList);return combiner.combine();};jsts.geom.util.GeometryCombiner.prototype.geomFactory=null;jsts.geom.util.GeometryCombiner.prototype.skipEmpty=false;jsts.geom.util.GeometryCombiner.prototype.inputGeoms;jsts.geom.util.GeometryCombiner.extractFactory=function(geoms){if(geoms.isEmpty())return null;return geoms.iterator().next().getFactory();};jsts.geom.util.GeometryCombiner.prototype.combine=function(){var elems=new javascript.util.ArrayList(),i;for(i=this.inputGeoms.iterator();i.hasNext();){var g=i.next();this.extractElements(g,elems);} -if(elems.size()===0){if(this.geomFactory!==null){return this.geomFactory.createGeometryCollection(null);} -return null;} -return this.geomFactory.buildGeometry(elems);};jsts.geom.util.GeometryCombiner.prototype.extractElements=function(geom,elems){if(geom===null){return;} -for(var i=0;imaxDistance){maxDistance=distance;maxIndex=k;}} -if(maxDistance<=this.distanceTolerance){for(var l=i+1;lsegmentIndex) -return 1;if(this.distdist) -return 1;return 0;};jsts.geomgraph.EdgeIntersection.prototype.isEndPoint=function(maxSegmentIndex){if(this.segmentIndex===0&&this.dist===0.0) -return true;if(this.segmentIndex===maxSegmentIndex) -return true;return false;};jsts.geomgraph.EdgeIntersection.prototype.toString=function(){return''+this.segmentIndex+this.dist;};(function(){var EdgeIntersection=jsts.geomgraph.EdgeIntersection;var TreeMap=javascript.util.TreeMap;jsts.geomgraph.EdgeIntersectionList=function(edge){this.nodeMap=new TreeMap();this.edge=edge;};jsts.geomgraph.EdgeIntersectionList.prototype.nodeMap=null;jsts.geomgraph.EdgeIntersectionList.prototype.edge=null;jsts.geomgraph.EdgeIntersectionList.prototype.isIntersection=function(pt){for(var it=this.iterator();it.hasNext();){var ei=it.next();if(ei.coord.equals(pt)){return true;}} -return false;};jsts.geomgraph.EdgeIntersectionList.prototype.add=function(intPt,segmentIndex,dist){var eiNew=new EdgeIntersection(intPt,segmentIndex,dist);var ei=this.nodeMap.get(eiNew);if(ei!==null){return ei;} -this.nodeMap.put(eiNew,eiNew);return eiNew;};jsts.geomgraph.EdgeIntersectionList.prototype.iterator=function(){return this.nodeMap.values().iterator();};jsts.geomgraph.EdgeIntersectionList.prototype.addEndpoints=function(){var maxSegIndex=this.edge.pts.length-1;this.add(this.edge.pts[0],0,0.0);this.add(this.edge.pts[maxSegIndex],maxSegIndex,0.0);};jsts.geomgraph.EdgeIntersectionList.prototype.addSplitEdges=function(edgeList) -{this.addEndpoints();var it=this.iterator();var eiPrev=it.next();while(it.hasNext()){var ei=it.next();var newEdge=this.createSplitEdge(eiPrev,ei);edgeList.add(newEdge);eiPrev=ei;}};jsts.geomgraph.EdgeIntersectionList.prototype.createSplitEdge=function(ei0,ei1){var npts=ei1.segmentIndex-ei0.segmentIndex+2;var lastSegStartPt=this.edge.pts[ei1.segmentIndex];var useIntPt1=ei1.dist>0.0||!ei1.coord.equals2D(lastSegStartPt);if(!useIntPt1){npts--;} -var pts=[];var ipt=0;pts[ipt++]=new jsts.geom.Coordinate(ei0.coord);for(var i=ei0.segmentIndex+1;i<=ei1.segmentIndex;i++){pts[ipt++]=this.edge.pts[i];} -if(useIntPt1)pts[ipt]=ei1.coord;return new jsts.geomgraph.Edge(pts,new jsts.geomgraph.Label(this.edge.label));};})();(function(){var AssertionFailedException=function(message){this.message=message;};AssertionFailedException.prototype=new Error();AssertionFailedException.prototype.name='AssertionFailedException';jsts.util.AssertionFailedException=AssertionFailedException;})();(function(){var AssertionFailedException=jsts.util.AssertionFailedException;jsts.util.Assert=function(){};jsts.util.Assert.isTrue=function(assertion,message){if(!assertion){if(message===null){throw new AssertionFailedException();}else{throw new AssertionFailedException(message);}}};jsts.util.Assert.equals=function(expectedValue,actualValue,message){if(!actualValue.equals(expectedValue)){throw new AssertionFailedException('Expected '+expectedValue+' but encountered '+actualValue+ -(message!=null?': '+message:''));}};jsts.util.Assert.shouldNeverReachHere=function(message){throw new AssertionFailedException('Should never reach here'+ -(message!=null?': '+message:''));};})();(function(){var Location=jsts.geom.Location;var Assert=jsts.util.Assert;var ArrayList=javascript.util.ArrayList;jsts.operation.relate.RelateComputer=function(arg){this.li=new jsts.algorithm.RobustLineIntersector();this.ptLocator=new jsts.algorithm.PointLocator();this.nodes=new jsts.geomgraph.NodeMap(new jsts.operation.relate.RelateNodeFactory());this.isolatedEdges=new ArrayList();this.arg=arg;};jsts.operation.relate.RelateComputer.prototype.li=null;jsts.operation.relate.RelateComputer.prototype.ptLocator=null;jsts.operation.relate.RelateComputer.prototype.arg=null;jsts.operation.relate.RelateComputer.prototype.nodes=null;jsts.operation.relate.RelateComputer.prototype.im=null;jsts.operation.relate.RelateComputer.prototype.isolatedEdges=null;jsts.operation.relate.RelateComputer.prototype.invalidPoint=null;jsts.operation.relate.RelateComputer.prototype.computeIM=function(){var im=new jsts.geom.IntersectionMatrix();im.set(Location.EXTERIOR,Location.EXTERIOR,2);if(!this.arg[0].getGeometry().getEnvelopeInternal().intersects(this.arg[1].getGeometry().getEnvelopeInternal())){this.computeDisjointIM(im);return im;} -this.arg[0].computeSelfNodes(this.li,false);this.arg[1].computeSelfNodes(this.li,false);var intersector=this.arg[0].computeEdgeIntersections(this.arg[1],this.li,false);this.computeIntersectionNodes(0);this.computeIntersectionNodes(1);this.copyNodesAndLabels(0);this.copyNodesAndLabels(1);this.labelIsolatedNodes();this.computeProperIntersectionIM(intersector,im);var eeBuilder=new jsts.operation.relate.EdgeEndBuilder();var ee0=eeBuilder.computeEdgeEnds(this.arg[0].getEdgeIterator());this.insertEdgeEnds(ee0);var ee1=eeBuilder.computeEdgeEnds(this.arg[1].getEdgeIterator());this.insertEdgeEnds(ee1);this.labelNodeEdges();this.labelIsolatedEdges(0,1);this.labelIsolatedEdges(1,0);this.updateIM(im);return im;};jsts.operation.relate.RelateComputer.prototype.insertEdgeEnds=function(ee){for(var i=ee.iterator();i.hasNext();){var e=i.next();this.nodes.add(e);}};jsts.operation.relate.RelateComputer.prototype.computeProperIntersectionIM=function(intersector,im){var dimA=this.arg[0].getGeometry().getDimension();var dimB=this.arg[1].getGeometry().getDimension();var hasProper=intersector.hasProperIntersection();var hasProperInterior=intersector.hasProperInteriorIntersection();if(dimA===2&&dimB===2){if(hasProper) -im.setAtLeast('212101212');} -else if(dimA===2&&dimB===1){if(hasProper) -im.setAtLeast('FFF0FFFF2');if(hasProperInterior) -im.setAtLeast('1FFFFF1FF');}else if(dimA===1&&dimB===2){if(hasProper) -im.setAtLeast('F0FFFFFF2');if(hasProperInterior) -im.setAtLeast('1F1FFFFFF');} -else if(dimA===1&&dimB===1){if(hasProperInterior) -im.setAtLeast('0FFFFFFFF');}};jsts.operation.relate.RelateComputer.prototype.copyNodesAndLabels=function(argIndex){for(var i=this.arg[argIndex].getNodeIterator();i.hasNext();){var graphNode=i.next();var newNode=this.nodes.addNode(graphNode.getCoordinate());newNode.setLabel(argIndex,graphNode.getLabel().getLocation(argIndex));}};jsts.operation.relate.RelateComputer.prototype.computeIntersectionNodes=function(argIndex){for(var i=this.arg[argIndex].getEdgeIterator();i.hasNext();){var e=i.next();var eLoc=e.getLabel().getLocation(argIndex);for(var eiIt=e.getEdgeIntersectionList().iterator();eiIt.hasNext();){var ei=eiIt.next();var n=this.nodes.addNode(ei.coord);if(eLoc===Location.BOUNDARY) -n.setLabelBoundary(argIndex);else{if(n.getLabel().isNull(argIndex)) -n.setLabel(argIndex,Location.INTERIOR);}}}};jsts.operation.relate.RelateComputer.prototype.labelIntersectionNodes=function(argIndex){for(var i=this.arg[argIndex].getEdgeIterator();i.hasNext();){var e=i.next();var eLoc=e.getLabel().getLocation(argIndex);for(var eiIt=e.getEdgeIntersectionList().iterator();eiIt.hasNext();){var ei=eiIt.next();var n=this.nodes.find(ei.coord);if(n.getLabel().isNull(argIndex)){if(eLoc===Location.BOUNDARY) -n.setLabelBoundary(argIndex);else -n.setLabel(argIndex,Location.INTERIOR);}}}};jsts.operation.relate.RelateComputer.prototype.computeDisjointIM=function(im){var ga=this.arg[0].getGeometry();if(!ga.isEmpty()){im.set(Location.INTERIOR,Location.EXTERIOR,ga.getDimension());im.set(Location.BOUNDARY,Location.EXTERIOR,ga.getBoundaryDimension());} -var gb=this.arg[1].getGeometry();if(!gb.isEmpty()){im.set(Location.EXTERIOR,Location.INTERIOR,gb.getDimension());im.set(Location.EXTERIOR,Location.BOUNDARY,gb.getBoundaryDimension());}};jsts.operation.relate.RelateComputer.prototype.labelNodeEdges=function(){for(var ni=this.nodes.iterator();ni.hasNext();){var node=ni.next();node.getEdges().computeLabelling(this.arg);}};jsts.operation.relate.RelateComputer.prototype.updateIM=function(im){for(var ei=this.isolatedEdges.iterator();ei.hasNext();){var e=ei.next();e.updateIM(im);} -for(var ni=this.nodes.iterator();ni.hasNext();){var node=ni.next();node.updateIM(im);node.updateIMFromEdges(im);}};jsts.operation.relate.RelateComputer.prototype.labelIsolatedEdges=function(thisIndex,targetIndex){for(var ei=this.arg[thisIndex].getEdgeIterator();ei.hasNext();){var e=ei.next();if(e.isIsolated()){this.labelIsolatedEdge(e,targetIndex,this.arg[targetIndex].getGeometry());this.isolatedEdges.add(e);}}};jsts.operation.relate.RelateComputer.prototype.labelIsolatedEdge=function(e,targetIndex,target){if(target.getDimension()>0){var loc=this.ptLocator.locate(e.getCoordinate(),target);e.getLabel().setAllLocations(targetIndex,loc);}else{e.getLabel().setAllLocations(targetIndex,Location.EXTERIOR);}};jsts.operation.relate.RelateComputer.prototype.labelIsolatedNodes=function(){for(var ni=this.nodes.iterator();ni.hasNext();){var n=ni.next();var label=n.getLabel();Assert.isTrue(label.getGeometryCount()>0,'node with empty label found');if(n.isIsolated()){if(label.isNull(0)) -this.labelIsolatedNode(n,0);else -this.labelIsolatedNode(n,1);}}};jsts.operation.relate.RelateComputer.prototype.labelIsolatedNode=function(n,targetIndex){var loc=this.ptLocator.locate(n.getCoordinate(),this.arg[targetIndex].getGeometry());n.getLabel().setAllLocations(targetIndex,loc);};})();(function(){var Assert=jsts.util.Assert;jsts.geomgraph.GraphComponent=function(label){this.label=label;};jsts.geomgraph.GraphComponent.prototype.label=null;jsts.geomgraph.GraphComponent.prototype._isInResult=false;jsts.geomgraph.GraphComponent.prototype._isCovered=false;jsts.geomgraph.GraphComponent.prototype._isCoveredSet=false;jsts.geomgraph.GraphComponent.prototype._isVisited=false;jsts.geomgraph.GraphComponent.prototype.getLabel=function(){return this.label;};jsts.geomgraph.GraphComponent.prototype.setLabel=function(label){if(arguments.length===2){this.setLabel2.apply(this,arguments);return;} -this.label=label;};jsts.geomgraph.GraphComponent.prototype.setInResult=function(isInResult){this._isInResult=isInResult;};jsts.geomgraph.GraphComponent.prototype.isInResult=function(){return this._isInResult;};jsts.geomgraph.GraphComponent.prototype.setCovered=function(isCovered){this._isCovered=isCovered;this._isCoveredSet=true;};jsts.geomgraph.GraphComponent.prototype.isCovered=function(){return this._isCovered;};jsts.geomgraph.GraphComponent.prototype.isCoveredSet=function(){return this._isCoveredSet;};jsts.geomgraph.GraphComponent.prototype.isVisited=function(){return this._isVisited;};jsts.geomgraph.GraphComponent.prototype.setVisited=function(isVisited){this._isVisited=isVisited;};jsts.geomgraph.GraphComponent.prototype.getCoordinate=function(){throw new jsts.error.AbstractMethodInvocationError();};jsts.geomgraph.GraphComponent.prototype.computeIM=function(im){throw new jsts.error.AbstractMethodInvocationError();};jsts.geomgraph.GraphComponent.prototype.isIsolated=function(){throw new jsts.error.AbstractMethodInvocationError();};jsts.geomgraph.GraphComponent.prototype.updateIM=function(im){Assert.isTrue(this.label.getGeometryCount()>=2,'found partial label');this.computeIM(im);};})();jsts.geomgraph.Node=function(coord,edges){this.coord=coord;this.edges=edges;this.label=new jsts.geomgraph.Label(0,jsts.geom.Location.NONE);};jsts.geomgraph.Node.prototype=new jsts.geomgraph.GraphComponent();jsts.geomgraph.Node.prototype.coord=null;jsts.geomgraph.Node.prototype.edges=null;jsts.geomgraph.Node.prototype.isIsolated=function(){return(this.label.getGeometryCount()==1);};jsts.geomgraph.Node.prototype.setLabel2=function(argIndex,onLocation){if(this.label===null){this.label=new jsts.geomgraph.Label(argIndex,onLocation);}else -this.label.setLocation(argIndex,onLocation);};jsts.geomgraph.Node.prototype.setLabelBoundary=function(argIndex){var loc=jsts.geom.Location.NONE;if(this.label!==null) -loc=this.label.getLocation(argIndex);var newLoc;switch(loc){case jsts.geom.Location.BOUNDARY:newLoc=jsts.geom.Location.INTERIOR;break;case jsts.geom.Location.INTERIOR:newLoc=jsts.geom.Location.BOUNDARY;break;default:newLoc=jsts.geom.Location.BOUNDARY;break;} -this.label.setLocation(argIndex,newLoc);};jsts.geomgraph.Node.prototype.add=function(e){this.edges.insert(e);e.setNode(this);};jsts.geomgraph.Node.prototype.getCoordinate=function(){return this.coord;};jsts.geomgraph.Node.prototype.getEdges=function(){return this.edges;};jsts.geomgraph.Node.prototype.isIncidentEdgeInResult=function(){for(var it=this.getEdges().getEdges().iterator();it.hasNext();){var de=it.next();if(de.getEdge().isInResult()) -return true;} -return false;};jsts.geom.Point=function(coordinate,factory){this.factory=factory;if(coordinate===undefined) -return;this.coordinate=coordinate;};jsts.geom.Point.prototype=new jsts.geom.Geometry();jsts.geom.Point.constructor=jsts.geom.Point;jsts.geom.Point.CLASS_NAME='jsts.geom.Point';jsts.geom.Point.prototype.coordinate=null;jsts.geom.Point.prototype.getX=function(){return this.coordinate.x;};jsts.geom.Point.prototype.getY=function(){return this.coordinate.y;};jsts.geom.Point.prototype.getCoordinate=function(){return this.coordinate;};jsts.geom.Point.prototype.getCoordinates=function(){return this.isEmpty()?[]:[this.coordinate];};jsts.geom.Point.prototype.getCoordinateSequence=function(){return this.isEmpty()?[]:[this.coordinate];};jsts.geom.Point.prototype.isEmpty=function(){return this.coordinate===null;};jsts.geom.Point.prototype.equalsExact=function(other,tolerance){if(!this.isEquivalentClass(other)){return false;} -if(this.isEmpty()&&other.isEmpty()){return true;} -return this.equal(other.getCoordinate(),this.getCoordinate(),tolerance);};jsts.geom.Point.prototype.getNumPoints=function(){return this.isEmpty()?0:1;};jsts.geom.Point.prototype.isSimple=function(){return true;};jsts.geom.Point.prototype.getBoundary=function(){return new jsts.geom.GeometryCollection(null);};jsts.geom.Point.prototype.computeEnvelopeInternal=function(){if(this.isEmpty()){return new jsts.geom.Envelope();} -return new jsts.geom.Envelope(this.coordinate);};jsts.geom.Point.prototype.apply=function(filter){if(filter instanceof jsts.geom.GeometryFilter||filter instanceof jsts.geom.GeometryComponentFilter){filter.filter(this);}else if(filter instanceof jsts.geom.CoordinateFilter){if(this.isEmpty()){return;} -filter.filter(this.getCoordinate());}};jsts.geom.Point.prototype.clone=function(){return new jsts.geom.Point(this.coordinate.clone(),this.factory);};jsts.geom.Point.prototype.getDimension=function(){return 0;};jsts.geom.Point.prototype.getBoundaryDimension=function(){return jsts.geom.Dimension.FALSE;};jsts.geom.Point.prototype.reverse=function(){return this.clone();};jsts.geom.Point.prototype.isValid=function(){if(!jsts.operation.valid.IsValidOp.isValid(this.getCoordinate())){return false;} -return true;};jsts.geom.Point.prototype.normalize=function(){};jsts.geom.Point.prototype.compareToSameClass=function(other){var point=other;return this.getCoordinate().compareTo(point.getCoordinate());};jsts.geom.Point.prototype.getGeometryType=function(){return'Point';};jsts.geom.Point.prototype.hashCode=function(){return'Point_'+this.coordinate.hashCode();};jsts.geom.Point.prototype.CLASS_NAME='jsts.geom.Point';jsts.geom.Dimension=function(){};jsts.geom.Dimension.P=0;jsts.geom.Dimension.L=1;jsts.geom.Dimension.A=2;jsts.geom.Dimension.FALSE=-1;jsts.geom.Dimension.TRUE=-2;jsts.geom.Dimension.DONTCARE=-3;jsts.geom.Dimension.toDimensionSymbol=function(dimensionValue){switch(dimensionValue){case jsts.geom.Dimension.FALSE:return'F';case jsts.geom.Dimension.TRUE:return'T';case jsts.geom.Dimension.DONTCARE:return'*';case jsts.geom.Dimension.P:return'0';case jsts.geom.Dimension.L:return'1';case jsts.geom.Dimension.A:return'2';} -throw new jsts.IllegalArgumentError('Unknown dimension value: '+ -dimensionValue);};jsts.geom.Dimension.toDimensionValue=function(dimensionSymbol){switch(dimensionSymbol.toUpperCase()){case'F':return jsts.geom.Dimension.FALSE;case'T':return jsts.geom.Dimension.TRUE;case'*':return jsts.geom.Dimension.DONTCARE;case'0':return jsts.geom.Dimension.P;case'1':return jsts.geom.Dimension.L;case'2':return jsts.geom.Dimension.A;} -throw new jsts.error.IllegalArgumentError('Unknown dimension symbol: '+ -dimensionSymbol);};(function(){var Dimension=jsts.geom.Dimension;jsts.geom.LineString=function(points,factory){this.factory=factory;this.points=points||[];};jsts.geom.LineString.prototype=new jsts.geom.Geometry();jsts.geom.LineString.constructor=jsts.geom.LineString;jsts.geom.LineString.prototype.points=null;jsts.geom.LineString.prototype.getCoordinates=function(){return this.points;};jsts.geom.LineString.prototype.getCoordinateSequence=function(){return this.points;};jsts.geom.LineString.prototype.getCoordinateN=function(n){return this.points[n];};jsts.geom.LineString.prototype.getCoordinate=function(){if(this.isEmpty()){return null;} -return this.getCoordinateN(0);};jsts.geom.LineString.prototype.getDimension=function(){return 1;};jsts.geom.LineString.prototype.getBoundaryDimension=function(){if(this.isClosed()){return Dimension.FALSE;} -return 0;};jsts.geom.LineString.prototype.isEmpty=function(){return this.points.length===0;};jsts.geom.LineString.prototype.getNumPoints=function(){return this.points.length;};jsts.geom.LineString.prototype.getPointN=function(n){return this.getFactory().createPoint(this.points[n]);};jsts.geom.LineString.prototype.getStartPoint=function(){if(this.isEmpty()){return null;} -return this.getPointN(0);};jsts.geom.LineString.prototype.getEndPoint=function(){if(this.isEmpty()){return null;} -return this.getPointN(this.getNumPoints()-1);};jsts.geom.LineString.prototype.isClosed=function(){if(this.isEmpty()){return false;} -return this.getCoordinateN(0).equals2D(this.getCoordinateN(this.points.length-1));};jsts.geom.LineString.prototype.isRing=function(){return this.isClosed()&&this.isSimple();};jsts.geom.LineString.prototype.getGeometryType=function(){return'LineString';};jsts.geom.LineString.prototype.getLength=function(){return jsts.algorithm.CGAlgorithms.computeLength(this.points);};jsts.geom.LineString.prototype.getBoundary=function(){return(new jsts.operation.BoundaryOp(this)).getBoundary();};jsts.geom.LineString.prototype.computeEnvelopeInternal=function(){if(this.isEmpty()){return new jsts.geom.Envelope();} -var env=new jsts.geom.Envelope();this.points.forEach(function(component){env.expandToInclude(component);});return env;};jsts.geom.LineString.prototype.equalsExact=function(other,tolerance){if(!this.isEquivalentClass(other)){return false;} -if(this.points.length!==other.points.length){return false;} -if(this.isEmpty()&&other.isEmpty()){return true;} -return this.points.reduce(function(equal,point,i){return equal&&jsts.geom.Geometry.prototype.equal(point,other.points[i],tolerance);});};jsts.geom.LineString.prototype.isEquivalentClass=function(other){return other instanceof jsts.geom.LineString;};jsts.geom.LineString.prototype.compareToSameClass=function(o){var line=o;var i=0,il=this.points.length;var j=0,jl=line.points.length;while(i0){this.points.reverse();} -return;}}};jsts.geom.LineString.prototype.CLASS_NAME='jsts.geom.LineString';})();(function(){jsts.geom.Polygon=function(shell,holes,factory){this.shell=shell||factory.createLinearRing(null);this.holes=holes||[];this.factory=factory;};jsts.geom.Polygon.prototype=new jsts.geom.Geometry();jsts.geom.Polygon.constructor=jsts.geom.Polygon;jsts.geom.Polygon.prototype.getCoordinate=function(){return this.shell.getCoordinate();};jsts.geom.Polygon.prototype.getCoordinates=function(){if(this.isEmpty()){return[];} -var coordinates=[];var k=-1;var shellCoordinates=this.shell.getCoordinates();for(var x=0;x0){cent.x=this.cg3.x/3/this.areasum2;cent.y=this.cg3.y/3/this.areasum2;}else if(this.totalLength>0){cent.x=this.lineCentSum.x/this.totalLength;cent.y=this.lineCentSum.y/this.totalLength;}else if(this.ptCount>0){cent.x=this.ptCentSum.x/this.ptCount;cent.y=this.ptCentSum.y/this.ptCount;}else{return null;} -return cent;};jsts.algorithm.Centroid.prototype.setBasePoint=function(basePt){if(this.areaBasePt===null){this.areaBasePt=basePt;}};jsts.algorithm.Centroid.prototype.addPolygon=function(poly){this.addShell(poly.getExteriorRing().getCoordinates());for(var i=0;i0){this.setBasePoint(pts[0]);} -var isPositiveArea=!jsts.algorithm.CGAlgorithms.isCCW(pts);for(var i=0;i0){this.addPoint(pts[0]);}};jsts.algorithm.Centroid.prototype.addPoint=function(pt){this.ptCount+=1;this.ptCentSum.x+=pt.x;this.ptCentSum.y+=pt.y;};(function(){var EdgeRing=function(factory){this.deList=new javascript.util.ArrayList();this.factory=factory;};EdgeRing.findEdgeRingContaining=function(testEr,shellList){var testRing=testEr.getRing();var testEnv=testRing.getEnvelopeInternal();var testPt=testRing.getCoordinateN(0);var minShell=null;var minEnv=null;for(var it=shellList.iterator();it.hasNext();){var tryShell=it.next();var tryRing=tryShell.getRing();var tryEnv=tryRing.getEnvelopeInternal();if(minShell!=null) -minEnv=minShell.getRing().getEnvelopeInternal();var isContained=false;if(tryEnv.equals(testEnv)) -continue;testPt=jsts.geom.CoordinateArrays.ptNotInList(testRing.getCoordinates(),tryRing.getCoordinates());if(tryEnv.contains(testEnv)&&jsts.algorithm.CGAlgorithms.isPointInRing(testPt,tryRing.getCoordinates())) -isContained=true;if(isContained){if(minShell==null||minEnv.contains(tryEnv)){minShell=tryShell;}}} -return minShell;};EdgeRing.ptNotInList=function(testPts,pts){for(var i=0;i=0;i--){coordList.add(coords[i],false);}}};jsts.operation.polygonize.EdgeRing=EdgeRing;})();(function(){var GraphComponent=function(){};GraphComponent.setVisited=function(i,visited){while(i.hasNext()){var comp=i.next();comp.setVisited(visited);}};GraphComponent.setMarked=function(i,marked){while(i.hasNext()){var comp=i.next();comp.setMarked(marked);}};GraphComponent.getComponentWithVisitedState=function(i,visitedState){while(i.hasNext()){var comp=i.next();if(comp.isVisited()==visitedState) -return comp;} -return null;};GraphComponent.prototype._isMarked=false;GraphComponent.prototype._isVisited=false;GraphComponent.prototype.data;GraphComponent.prototype.isVisited=function(){return this._isVisited;};GraphComponent.prototype.setVisited=function(isVisited){this._isVisited=isVisited;};GraphComponent.prototype.isMarked=function(){return this._isMarked;};GraphComponent.prototype.setMarked=function(isMarked){this._isMarked=isMarked;};GraphComponent.prototype.setContext=function(data){this.data=data;};GraphComponent.prototype.getContext=function(){return data;};GraphComponent.prototype.setData=function(data){this.data=data;};GraphComponent.prototype.getData=function(){return data;};GraphComponent.prototype.isRemoved=function(){throw new jsts.error.AbstractMethodInvocationError();};jsts.planargraph.GraphComponent=GraphComponent;})();(function(){var GraphComponent=jsts.planargraph.GraphComponent;var Edge=function(de0,de1){if(de0===undefined){return;} -this.setDirectedEdges(de0,de1);};Edge.prototype=new GraphComponent();Edge.prototype.dirEdge=null;Edge.prototype.setDirectedEdges=function(de0,de1){this.dirEdge=[de0,de1];de0.setEdge(this);de1.setEdge(this);de0.setSym(de1);de1.setSym(de0);de0.getFromNode().addOutEdge(de0);de1.getFromNode().addOutEdge(de1);};Edge.prototype.getDirEdge=function(i){if(i instanceof jsts.planargraph.Node){this.getDirEdge2(i);} -return this.dirEdge[i];};Edge.prototype.getDirEdge2=function(fromNode){if(this.dirEdge[0].getFromNode()==fromNode) -return this.dirEdge[0];if(this.dirEdge[1].getFromNode()==fromNode) -return this.dirEdge[1];return null;};Edge.prototype.getOppositeNode=function(node){if(this.dirEdge[0].getFromNode()==node) -return this.dirEdge[0].getToNode();if(this.dirEdge[1].getFromNode()==node) -return this.dirEdge[1].getToNode();return null;};Edge.prototype.remove=function(){this.dirEdge=null;};Edge.prototype.isRemoved=function(){return dirEdge==null;};jsts.planargraph.Edge=Edge;})();jsts.operation.polygonize.PolygonizeEdge=function(line){this.line=line;};jsts.operation.polygonize.PolygonizeEdge.prototype=new jsts.planargraph.Edge();jsts.operation.polygonize.PolygonizeEdge.prototype.line=null;jsts.operation.polygonize.PolygonizeEdge.prototype.getLine=function(){return this.line;};(function(){var ArrayList=javascript.util.ArrayList;var GraphComponent=jsts.planargraph.GraphComponent;var DirectedEdge=function(from,to,directionPt,edgeDirection){if(from===undefined){return;} -this.from=from;this.to=to;this.edgeDirection=edgeDirection;this.p0=from.getCoordinate();this.p1=directionPt;var dx=this.p1.x-this.p0.x;var dy=this.p1.y-this.p0.y;this.quadrant=jsts.geomgraph.Quadrant.quadrant(dx,dy);this.angle=Math.atan2(dy,dx);};DirectedEdge.prototype=new GraphComponent();DirectedEdge.toEdges=function(dirEdges){var edges=new ArrayList();for(var i=dirEdges.iterator();i.hasNext();){edges.add((i.next()).parentEdge);} -return edges;};DirectedEdge.prototype.parentEdge=null;DirectedEdge.prototype.from=null;DirectedEdge.prototype.to=null;DirectedEdge.prototype.p0=null;DirectedEdge.prototype.p1=null;DirectedEdge.prototype.sym=null;DirectedEdge.prototype.edgeDirection=null;DirectedEdge.prototype.quadrant=null;DirectedEdge.prototype.angle=null;DirectedEdge.prototype.getEdge=function(){return this.parentEdge;};DirectedEdge.prototype.setEdge=function(parentEdge){this.parentEdge=parentEdge;};DirectedEdge.prototype.getQuadrant=function(){return this.quadrant;};DirectedEdge.prototype.getDirectionPt=function(){return this.p1;};DirectedEdge.prototype.getEdgeDirection=function(){return this.edgeDirection;};DirectedEdge.prototype.getFromNode=function(){return this.from;};DirectedEdge.prototype.getToNode=function(){return this.to;};DirectedEdge.prototype.getCoordinate=function(){return this.from.getCoordinate();};DirectedEdge.prototype.getAngle=function(){return this.angle;};DirectedEdge.prototype.getSym=function(){return this.sym;};DirectedEdge.prototype.setSym=function(sym){this.sym=sym;};DirectedEdge.prototype.remove=function(){this.sym=null;this.parentEdge=null;};DirectedEdge.prototype.isRemoved=function(){return this.parentEdge==null;};DirectedEdge.prototype.compareTo=function(obj){var de=obj;return this.compareDirection(de);};DirectedEdge.prototype.compareDirection=function(e){if(this.quadrant>e.quadrant) -return 1;if(this.quadrant1){if(intNodes==null) -intNodes=new ArrayList();intNodes.add(node);} -de=de.getNext();Assert.isTrue(de!=null,'found null DE in ring');Assert.isTrue(de==startDE||!de.isInRing(),'found DE already in ring');}while(de!=startDE);return intNodes;};PolygonizeGraph.prototype.getEdgeRings=function(){this.computeNextCWEdges();PolygonizeGraph.label(this.dirEdges,-1);var maximalRings=PolygonizeGraph.findLabeledEdgeRings(this.dirEdges);this.convertMaximalToMinimalEdgeRings(maximalRings);var edgeRingList=new ArrayList();for(var i=this.dirEdges.iterator();i.hasNext();){var de=i.next();if(de.isMarked()) -continue;if(de.isInRing()) -continue;var er=this.findEdgeRing(de);edgeRingList.add(er);} -return edgeRingList;};PolygonizeGraph.findLabeledEdgeRings=function(dirEdges){var edgeRingStarts=new ArrayList();var currLabel=1;for(var i=dirEdges.iterator();i.hasNext();){var de=i.next();if(de.isMarked()) -continue;if(de.getLabel()>=0) -continue;edgeRingStarts.add(de);var edges=PolygonizeGraph.findDirEdgesInRing(de);PolygonizeGraph.label(edges,currLabel);currLabel++;} -return edgeRingStarts;};PolygonizeGraph.prototype.deleteCutEdges=function(){this.computeNextCWEdges();PolygonizeGraph.findLabeledEdgeRings(this.dirEdges);var cutLines=new ArrayList();for(var i=this.dirEdges.iterator();i.hasNext();){var de=i.next();if(de.isMarked()) -continue;var sym=de.getSym();if(de.getLabel()==sym.getLabel()){de.setMarked(true);sym.setMarked(true);var e=de.getEdge();cutLines.add(e.getLine());}} -return cutLines;};PolygonizeGraph.label=function(dirEdges,label){for(var i=dirEdges.iterator();i.hasNext();){var de=i.next();de.setLabel(label);}};PolygonizeGraph.computeNextCWEdges=function(node){var deStar=node.getOutEdges();var startDE=null;var prevDE=null;for(var i=deStar.getEdges().iterator();i.hasNext();){var outDE=i.next();if(outDE.isMarked()) -continue;if(startDE==null) -startDE=outDE;if(prevDE!=null){var sym=prevDE.getSym();sym.setNext(outDE);} -prevDE=outDE;} -if(prevDE!=null){var sym=prevDE.getSym();sym.setNext(startDE);}};PolygonizeGraph.computeNextCCWEdges=function(node,label){var deStar=node.getOutEdges();var firstOutDE=null;var prevInDE=null;var edges=deStar.getEdges();for(var i=edges.size()-1;i>=0;i--){var de=edges.get(i);var sym=de.getSym();var outDE=null;if(de.getLabel()==label) -outDE=de;var inDE=null;if(sym.getLabel()==label) -inDE=sym;if(outDE==null&&inDE==null) -continue;if(inDE!=null){prevInDE=inDE;} -if(outDE!=null){if(prevInDE!=null){prevInDE.setNext(outDE);prevInDE=null;} -if(firstOutDE==null) -firstOutDE=outDE;}} -if(prevInDE!=null){Assert.isTrue(firstOutDE!=null);prevInDE.setNext(firstOutDE);}};PolygonizeGraph.findDirEdgesInRing=function(startDE){var de=startDE;var edges=new ArrayList();do{edges.add(de);de=de.getNext();Assert.isTrue(de!=null,'found null DE in ring');Assert.isTrue(de==startDE||!de.isInRing(),'found DE already in ring');}while(de!=startDE);return edges;};PolygonizeGraph.prototype.findEdgeRing=function(startDE){var de=startDE;var er=new EdgeRing(this.factory);do{er.add(de);de.setRing(er);de=de.getNext();Assert.isTrue(de!=null,'found null DE in ring');Assert.isTrue(de==startDE||!de.isInRing(),'found DE already in ring');}while(de!=startDE);return er;};PolygonizeGraph.prototype.deleteDangles=function(){var nodesToRemove=this.findNodesOfDegree(1);var dangleLines=new HashSet();var nodeStack=new Stack();for(var i=nodesToRemove.iterator();i.hasNext();){nodeStack.push(i.next());} -while(!nodeStack.isEmpty()){var node=nodeStack.pop();PolygonizeGraph.deleteAllEdges(node);var nodeOutEdges=node.getOutEdges().getEdges();for(var i=nodeOutEdges.iterator();i.hasNext();){var de=i.next();de.setMarked(true);var sym=de.getSym();if(sym!=null) -sym.setMarked(true);var e=de.getEdge();dangleLines.add(e.getLine());var toNode=de.getToNode();if(PolygonizeGraph.getDegreeNonDeleted(toNode)==1) -nodeStack.push(toNode);}} -return dangleLines;};PolygonizeGraph.prototype.computeDepthParity=function(){while(true){var de=null;if(de==null) -return;this.computeDepthParity(de);}};PolygonizeGraph.prototype.computeDepthParity=function(de){};jsts.operation.polygonize.PolygonizeGraph=PolygonizeGraph;})();jsts.index.strtree.Interval=function(){var other;if(arguments.length===1){other=arguments[0];return jsts.index.strtree.Interval(other.min,other.max);}else if(arguments.length===2){jsts.util.Assert.isTrue(this.min<=this.max);this.min=arguments[0];this.max=arguments[1];}};jsts.index.strtree.Interval.prototype.min=null;jsts.index.strtree.Interval.prototype.max=null;jsts.index.strtree.Interval.prototype.getCentre=function(){return(this.min+this.max)/2;};jsts.index.strtree.Interval.prototype.expandToInclude=function(other){this.max=Math.max(this.max,other.max);this.min=Math.min(this.min,other.min);return this;};jsts.index.strtree.Interval.prototype.intersects=function(other){return!(other.min>this.max||other.max1;if(isCollection){if(geom0 instanceof jsts.geom.Polygon){return this.createMultiPolygon(geomList.toArray());}else if(geom0 instanceof jsts.geom.LineString){return this.createMultiLineString(geomList.toArray());}else if(geom0 instanceof jsts.geom.Point){return this.createMultiPoint(geomList.toArray());} -jsts.util.Assert.shouldNeverReachHere('Unhandled class: '+geom0);} -return geom0;};jsts.geom.GeometryFactory.prototype.createGeometryCollection=function(geometries){return new jsts.geom.GeometryCollection(geometries,this);};jsts.geom.GeometryFactory.prototype.toGeometry=function(envelope){if(envelope.isNull()){return this.createPoint(null);} -if(envelope.getMinX()===envelope.getMaxX()&&envelope.getMinY()===envelope.getMaxY()){return this.createPoint(new jsts.geom.Coordinate(envelope.getMinX(),envelope.getMinY()));} -if(envelope.getMinX()===envelope.getMaxX()||envelope.getMinY()===envelope.getMaxY()){return this.createLineString([new jsts.geom.Coordinate(envelope.getMinX(),envelope.getMinY()),new jsts.geom.Coordinate(envelope.getMaxX(),envelope.getMaxY())]);} -return this.createPolygon(this.createLinearRing([new jsts.geom.Coordinate(envelope.getMinX(),envelope.getMinY()),new jsts.geom.Coordinate(envelope.getMinX(),envelope.getMaxY()),new jsts.geom.Coordinate(envelope.getMaxX(),envelope.getMaxY()),new jsts.geom.Coordinate(envelope.getMaxX(),envelope.getMinY()),new jsts.geom.Coordinate(envelope.getMinX(),envelope.getMinY())]),null);};jsts.geomgraph.NodeFactory=function(){};jsts.geomgraph.NodeFactory.prototype.createNode=function(coord){return new jsts.geomgraph.Node(coord,null);};(function(){jsts.geomgraph.Position=function(){};jsts.geomgraph.Position.ON=0;jsts.geomgraph.Position.LEFT=1;jsts.geomgraph.Position.RIGHT=2;jsts.geomgraph.Position.opposite=function(position){if(position===jsts.geomgraph.Position.LEFT){return jsts.geomgraph.Position.RIGHT;} -if(position===jsts.geomgraph.Position.RIGHT){return jsts.geomgraph.Position.LEFT;} -return position;};})();jsts.geomgraph.TopologyLocation=function(){this.location=[];if(arguments.length===3){var on=arguments[0];var left=arguments[1];var right=arguments[2];this.init(3);this.location[jsts.geomgraph.Position.ON]=on;this.location[jsts.geomgraph.Position.LEFT]=left;this.location[jsts.geomgraph.Position.RIGHT]=right;}else if(arguments[0]instanceof jsts.geomgraph.TopologyLocation){var gl=arguments[0];this.init(gl.location.length);if(gl!=null){for(var i=0;i1;};jsts.geomgraph.TopologyLocation.prototype.isLine=function(){return this.location.length===1;};jsts.geomgraph.TopologyLocation.prototype.flip=function(){if(this.location.length<=1) -return;var temp=this.location[jsts.geomgraph.Position.LEFT];this.location[jsts.geomgraph.Position.LEFT]=this.location[jsts.geomgraph.Position.RIGHT];this.location[jsts.geomgraph.Position.RIGHT]=temp;};jsts.geomgraph.TopologyLocation.prototype.setAllLocations=function(locValue){for(var i=0;ithis.location.length){var newLoc=[];newLoc[jsts.geomgraph.Position.ON]=this.location[jsts.geomgraph.Position.ON];newLoc[jsts.geomgraph.Position.LEFT]=jsts.geom.Location.NONE;newLoc[jsts.geomgraph.Position.RIGHT]=jsts.geom.Location.NONE;this.location=newLoc;} -for(var i=0;ithis.maxNodeDegree) -this.maxNodeDegree=degree;de=this.getNext(de);}while(de!==this.startDe);this.maxNodeDegree*=2;};jsts.geomgraph.EdgeRing.prototype.setInResult=function(){var de=this.startDe;do{de.getEdge().setInResult(true);de=de.getNext();}while(de!=this.startDe);};jsts.geomgraph.EdgeRing.prototype.mergeLabel=function(deLabel){this.mergeLabel2(deLabel,0);this.mergeLabel2(deLabel,1);};jsts.geomgraph.EdgeRing.prototype.mergeLabel2=function(deLabel,geomIndex){var loc=deLabel.getLocation(geomIndex,jsts.geomgraph.Position.RIGHT);if(loc==jsts.geom.Location.NONE) -return;if(this.label.getLocation(geomIndex)===jsts.geom.Location.NONE){this.label.setLocation(geomIndex,loc);return;}};jsts.geomgraph.EdgeRing.prototype.addPoints=function(edge,isForward,isFirstEdge){var edgePts=edge.getCoordinates();if(isForward){var startIndex=1;if(isFirstEdge) -startIndex=0;for(var i=startIndex;i=0;i--){this.pts.push(edgePts[i]);}}};jsts.geomgraph.EdgeRing.prototype.containsPoint=function(p){var shell=this.getLinearRing();var env=shell.getEnvelopeInternal();if(!env.contains(p)) -return false;if(!jsts.algorithm.CGAlgorithms.isPointInRing(p,shell.getCoordinates())) -return false;for(var i=0;i1,'Node capacity must be greater than 1');this.nodeCapacity=nodeCapacity;};jsts.index.strtree.AbstractSTRtree.IntersectsOp=function(){};jsts.index.strtree.AbstractSTRtree.IntersectsOp.prototype.intersects=function(aBounds,bBounds){throw new jsts.error.AbstractMethodInvocationError();};jsts.index.strtree.AbstractSTRtree.prototype.root=null;jsts.index.strtree.AbstractSTRtree.prototype.built=false;jsts.index.strtree.AbstractSTRtree.prototype.itemBoundables=null;jsts.index.strtree.AbstractSTRtree.prototype.nodeCapacity=null;jsts.index.strtree.AbstractSTRtree.prototype.build=function(){jsts.util.Assert.isTrue(!this.built);this.root=this.itemBoundables.length===0?this.createNode(0):this.createHigherLevels(this.itemBoundables,-1);this.built=true;};jsts.index.strtree.AbstractSTRtree.prototype.createNode=function(level){throw new jsts.error.AbstractMethodInvocationError();};jsts.index.strtree.AbstractSTRtree.prototype.createParentBoundables=function(childBoundables,newLevel){jsts.util.Assert.isTrue(!(childBoundables.length===0));var parentBoundables=[];parentBoundables.push(this.createNode(newLevel));var sortedChildBoundables=[];for(var i=0;ib?1:amaxChildDepth) -maxChildDepth=childDepth;}} -return maxChildDepth+1;};jsts.index.strtree.AbstractSTRtree.prototype.insert=function(bounds,item){jsts.util.Assert.isTrue(!this.built,'Cannot insert items into an STR packed R-tree after it has been built.');this.itemBoundables.push(new jsts.index.strtree.ItemBoundable(bounds,item));};jsts.index.strtree.AbstractSTRtree.prototype.query=function(searchBounds){if(arguments.length>1){this.query2.apply(this,arguments);} -if(!this.built){this.build();} -var matches=[];if(this.itemBoundables.length===0){jsts.util.Assert.isTrue(this.root.getBounds()===null);return matches;} -if(this.getIntersectsOp().intersects(this.root.getBounds(),searchBounds)){this.query3(searchBounds,this.root,matches);} -return matches;};jsts.index.strtree.AbstractSTRtree.prototype.query2=function(searchBounds,visitor){if(arguments.length>2){this.query3.apply(this,arguments);} -if(!this.built){this.build();} -if(this.itemBoundables.length===0){jsts.util.Assert.isTrue(this.root.getBounds()===null);} -if(this.getIntersectsOp().intersects(this.root.getBounds(),searchBounds)){this.query4(searchBounds,this.root,visitor);}};jsts.index.strtree.AbstractSTRtree.prototype.query3=function(searchBounds,node,matches){if(!(arguments[2]instanceof Array)){this.query4.apply(this,arguments);} -var childBoundables=node.getChildBoundables();for(var i=0;i1){this.boundablesAtLevel2.apply(this,arguments);return;} -var boundables=[];this.boundablesAtLevel2(level,this.root,boundables);return boundables;};jsts.index.strtree.AbstractSTRtree.prototype.boundablesAtLevel2=function(level,top,boundables){jsts.util.Assert.isTrue(level>-2);if(top.getLevel()===level){boundables.add(top);return;} -var childBoundables=node.getChildBoundables();for(var i=0;i0);var parentBoundables=[];for(var i=0;i0.0){var bndPair=priQ.pop();var currentDistance=bndPair.getDistance();if(currentDistance>=distanceLowerBound) -break;if(bndPair.isLeaves()){distanceLowerBound=currentDistance;minPair=bndPair;}else{bndPair.expandToQueue(priQ,distanceLowerBound);}} -return[minPair.getBoundable(0).getItem(),minPair.getBoundable(1).getItem()];};jsts.noding.SegmentString=function(){};jsts.noding.SegmentString.prototype.getData=jsts.abstractFunc;jsts.noding.SegmentString.prototype.setData=jsts.abstractFunc;jsts.noding.SegmentString.prototype.size=jsts.abstractFunc;jsts.noding.SegmentString.prototype.getCoordinate=jsts.abstractFunc;jsts.noding.SegmentString.prototype.getCoordinates=jsts.abstractFunc;jsts.noding.SegmentString.prototype.isClosed=jsts.abstractFunc;jsts.noding.NodableSegmentString=function(){};jsts.noding.NodableSegmentString.prototype=new jsts.noding.SegmentString();jsts.noding.NodableSegmentString.prototype.addIntersection=jsts.abstractFunc;jsts.noding.NodedSegmentString=function(pts,data){this.nodeList=new jsts.noding.SegmentNodeList(this);this.pts=pts;this.data=data;};jsts.noding.NodedSegmentString.prototype=new jsts.noding.NodableSegmentString();jsts.noding.NodedSegmentString.constructor=jsts.noding.NodedSegmentString;jsts.noding.NodedSegmentString.getNodedSubstrings=function(segStrings){if(arguments.length===2){jsts.noding.NodedSegmentString.getNodedSubstrings2.apply(this,arguments);return;} -var resultEdgelist=new javascript.util.ArrayList();jsts.noding.NodedSegmentString.getNodedSubstrings2(segStrings,resultEdgelist);return resultEdgelist;};jsts.noding.NodedSegmentString.getNodedSubstrings2=function(segStrings,resultEdgelist){for(var i=segStrings.iterator();i.hasNext();){var ss=i.next();ss.getNodeList().addSplitEdges(resultEdgelist);}};jsts.noding.NodedSegmentString.prototype.nodeList=null;jsts.noding.NodedSegmentString.prototype.pts=null;jsts.noding.NodedSegmentString.prototype.data=null;jsts.noding.NodedSegmentString.prototype.getData=function(){return this.data;};jsts.noding.NodedSegmentString.prototype.setData=function(data){this.data=data;};jsts.noding.NodedSegmentString.prototype.getNodeList=function(){return this.nodeList;};jsts.noding.NodedSegmentString.prototype.size=function(){return this.pts.length;};jsts.noding.NodedSegmentString.prototype.getCoordinate=function(i){return this.pts[i];};jsts.noding.NodedSegmentString.prototype.getCoordinates=function(){return this.pts;};jsts.noding.NodedSegmentString.prototype.isClosed=function(){return this.pts[0].equals(this.pts[this.pts.length-1]);};jsts.noding.NodedSegmentString.prototype.getSegmentOctant=function(index){if(index===this.pts.length-1) -return-1;return this.safeOctant(this.getCoordinate(index),this.getCoordinate(index+1));};jsts.noding.NodedSegmentString.prototype.safeOctant=function(p0,p1){if(p0.equals2D(p1)) -return 0;return jsts.noding.Octant.octant(p0,p1);};jsts.noding.NodedSegmentString.prototype.addIntersections=function(li,segmentIndex,geomIndex){for(var i=0;i=pts.length-1){return pts.length-1;} -var chainQuad=jsts.geomgraph.Quadrant.quadrant(pts[safeStart],pts[safeStart+1]);var last=start+1;while(lastdy){dist=dx;}else{dist=dy;}}else{var pdx=Math.abs(p.x-p0.x);var pdy=Math.abs(p.y-p0.y);if(dx>dy){dist=pdx;}else{dist=pdy;} -if(dist===0.0&&!p.equals(p0)){dist=Math.max(pdx,pdy);}} -if(dist===0.0&&!p.equals(p0)){throw new jsts.error.IllegalArgumentError('Bad distance calculation');} -return dist;};jsts.algorithm.LineIntersector.nonRobustComputeEdgeDistance=function(p,p1,p2){var dx=p.x-p1.x;var dy=p.y-p1.y;var dist=Math.sqrt(dx*dx+dy*dy);if(!(dist===0.0&&!p.equals(p1))){throw new jsts.error.IllegalArgumentError('Invalid distance calculation');} -return dist;};jsts.algorithm.LineIntersector.prototype.result=null;jsts.algorithm.LineIntersector.prototype.inputLines=null;jsts.algorithm.LineIntersector.prototype.intPt=null;jsts.algorithm.LineIntersector.prototype.intLineIndex=null;jsts.algorithm.LineIntersector.prototype._isProper=null;jsts.algorithm.LineIntersector.prototype.pa=null;jsts.algorithm.LineIntersector.prototype.pb=null;jsts.algorithm.LineIntersector.prototype.precisionModel=null;jsts.algorithm.LineIntersector.prototype.computeIntersection=function(p,p1,p2){throw new jsts.error.AbstractMethodInvocationError();};jsts.algorithm.LineIntersector.prototype.isCollinear=function(){return this.result===jsts.algorithm.LineIntersector.COLLINEAR_INTERSECTION;};jsts.algorithm.LineIntersector.prototype.computeIntersection=function(p1,p2,p3,p4){this.inputLines[0][0]=p1;this.inputLines[0][1]=p2;this.inputLines[1][0]=p3;this.inputLines[1][1]=p4;this.result=this.computeIntersect(p1,p2,p3,p4);};jsts.algorithm.LineIntersector.prototype.computeIntersect=function(p1,p2,q1,q2){throw new jsts.error.AbstractMethodInvocationError();};jsts.algorithm.LineIntersector.prototype.isEndPoint=function(){return this.hasIntersection()&&!this._isProper;};jsts.algorithm.LineIntersector.prototype.hasIntersection=function(){return this.result!==jsts.algorithm.LineIntersector.NO_INTERSECTION;};jsts.algorithm.LineIntersector.prototype.getIntersectionNum=function(){return this.result;};jsts.algorithm.LineIntersector.prototype.getIntersection=function(intIndex){return this.intPt[intIndex];};jsts.algorithm.LineIntersector.prototype.computeIntLineIndex=function(){if(this.intLineIndex===null){this.intLineIndex=[[],[]];this.computeIntLineIndex(0);this.computeIntLineIndex(1);}};jsts.algorithm.LineIntersector.prototype.isIntersection=function(pt){var i;for(i=0;idist1){this.intLineIndex[segmentIndex][0]=0;this.intLineIndex[segmentIndex][1]=1;}else{this.intLineIndex[segmentIndex][0]=1;this.intLineIndex[segmentIndex][1]=0;}};jsts.algorithm.LineIntersector.prototype.getEdgeDistance=function(segmentIndex,intIndex){var dist=jsts.algorithm.LineIntersector.computeEdgeDistance(this.intPt[intIndex],this.inputLines[segmentIndex][0],this.inputLines[segmentIndex][1]);return dist;};jsts.algorithm.RobustLineIntersector=function(){jsts.algorithm.RobustLineIntersector.prototype.constructor.call(this);};jsts.algorithm.RobustLineIntersector.prototype=new jsts.algorithm.LineIntersector();jsts.algorithm.RobustLineIntersector.prototype.computeIntersection=function(p,p1,p2){if(arguments.length===4){jsts.algorithm.LineIntersector.prototype.computeIntersection.apply(this,arguments);return;} -this._isProper=false;if(jsts.geom.Envelope.intersects(p1,p2,p)){if((jsts.algorithm.CGAlgorithms.orientationIndex(p1,p2,p)===0)&&(jsts.algorithm.CGAlgorithms.orientationIndex(p2,p1,p)===0)){this._isProper=true;if(p.equals(p1)||p.equals(p2)){this._isProper=false;} -this.result=jsts.algorithm.LineIntersector.POINT_INTERSECTION;return;}} -this.result=jsts.algorithm.LineIntersector.NO_INTERSECTION;};jsts.algorithm.RobustLineIntersector.prototype.computeIntersect=function(p1,p2,q1,q2){this._isProper=false;if(!jsts.geom.Envelope.intersects(p1,p2,q1,q2)){return jsts.algorithm.LineIntersector.NO_INTERSECTION;} -var Pq1=jsts.algorithm.CGAlgorithms.orientationIndex(p1,p2,q1);var Pq2=jsts.algorithm.CGAlgorithms.orientationIndex(p1,p2,q2);if((Pq1>0&&Pq2>0)||(Pq1<0&&Pq2<0)){return jsts.algorithm.LineIntersector.NO_INTERSECTION;} -var Qp1=jsts.algorithm.CGAlgorithms.orientationIndex(q1,q2,p1);var Qp2=jsts.algorithm.CGAlgorithms.orientationIndex(q1,q2,p2);if((Qp1>0&&Qp2>0)||(Qp1<0&&Qp2<0)){return jsts.algorithm.LineIntersector.NO_INTERSECTION;} -var collinear=Pq1===0&&Pq2===0&&Qp1===0&&Qp2===0;if(collinear){return this.computeCollinearIntersection(p1,p2,q1,q2);} -if(Pq1===0||Pq2===0||Qp1===0||Qp2===0){this._isProper=false;if(p1.equals2D(q1)||p1.equals2D(q2)){this.intPt[0]=p1;}else if(p2.equals2D(q1)||p2.equals2D(q2)){this.intPt[0]=p2;} -else if(Pq1===0){this.intPt[0]=new jsts.geom.Coordinate(q1);}else if(Pq2===0){this.intPt[0]=new jsts.geom.Coordinate(q2);}else if(Qp1===0){this.intPt[0]=new jsts.geom.Coordinate(p1);}else if(Qp2===0){this.intPt[0]=new jsts.geom.Coordinate(p2);}}else{this._isProper=true;this.intPt[0]=this.intersection(p1,p2,q1,q2);} -return jsts.algorithm.LineIntersector.POINT_INTERSECTION;};jsts.algorithm.RobustLineIntersector.prototype.computeCollinearIntersection=function(p1,p2,q1,q2){var p1q1p2=jsts.geom.Envelope.intersects(p1,p2,q1);var p1q2p2=jsts.geom.Envelope.intersects(p1,p2,q2);var q1p1q2=jsts.geom.Envelope.intersects(q1,q2,p1);var q1p2q2=jsts.geom.Envelope.intersects(q1,q2,p2);if(p1q1p2&&p1q2p2){this.intPt[0]=q1;this.intPt[1]=q2;return jsts.algorithm.LineIntersector.COLLINEAR_INTERSECTION;} -if(q1p1q2&&q1p2q2){this.intPt[0]=p1;this.intPt[1]=p2;return jsts.algorithm.LineIntersector.COLLINEAR_INTERSECTION;} -if(p1q1p2&&q1p1q2){this.intPt[0]=q1;this.intPt[1]=p1;return q1.equals(p1)&&!p1q2p2&&!q1p2q2?jsts.algorithm.LineIntersector.POINT_INTERSECTION:jsts.algorithm.LineIntersector.COLLINEAR_INTERSECTION;} -if(p1q1p2&&q1p2q2){this.intPt[0]=q1;this.intPt[1]=p2;return q1.equals(p2)&&!p1q2p2&&!q1p1q2?jsts.algorithm.LineIntersector.POINT_INTERSECTION:jsts.algorithm.LineIntersector.COLLINEAR_INTERSECTION;} -if(p1q2p2&&q1p1q2){this.intPt[0]=q2;this.intPt[1]=p1;return q2.equals(p1)&&!p1q1p2&&!q1p2q2?jsts.algorithm.LineIntersector.POINT_INTERSECTION:jsts.algorithm.LineIntersector.COLLINEAR_INTERSECTION;} -if(p1q2p2&&q1p2q2){this.intPt[0]=q2;this.intPt[1]=p2;return q2.equals(p2)&&!p1q1p2&&!q1p1q2?jsts.algorithm.LineIntersector.POINT_INTERSECTION:jsts.algorithm.LineIntersector.COLLINEAR_INTERSECTION;} -return jsts.algorithm.LineIntersector.NO_INTERSECTION;};jsts.algorithm.RobustLineIntersector.prototype.intersection=function(p1,p2,q1,q2){var intPt=this.intersectionWithNormalization(p1,p2,q1,q2);if(!this.isInSegmentEnvelopes(intPt)){intPt=jsts.algorithm.CentralEndpointIntersector.getIntersection(p1,p2,q1,q2);} -if(this.precisionModel!==null){this.precisionModel.makePrecise(intPt);} -return intPt;};jsts.algorithm.RobustLineIntersector.prototype.intersectionWithNormalization=function(p1,p2,q1,q2){var n1=new jsts.geom.Coordinate(p1);var n2=new jsts.geom.Coordinate(p2);var n3=new jsts.geom.Coordinate(q1);var n4=new jsts.geom.Coordinate(q2);var normPt=new jsts.geom.Coordinate();this.normalizeToEnvCentre(n1,n2,n3,n4,normPt);var intPt=this.safeHCoordinateIntersection(n1,n2,n3,n4);intPt.x+=normPt.x;intPt.y+=normPt.y;return intPt;};jsts.algorithm.RobustLineIntersector.prototype.safeHCoordinateIntersection=function(p1,p2,q1,q2){var intPt=null;try{intPt=jsts.algorithm.HCoordinate.intersection(p1,p2,q1,q2);}catch(e){if(e instanceof jsts.error.NotRepresentableError){intPt=jsts.algorithm.CentralEndpointIntersector.getIntersection(p1,p2,q1,q2);}else{throw e;}} -return intPt;};jsts.algorithm.RobustLineIntersector.prototype.normalizeToMinimum=function(n1,n2,n3,n4,normPt){normPt.x=this.smallestInAbsValue(n1.x,n2.x,n3.x,n4.x);normPt.y=this.smallestInAbsValue(n1.y,n2.y,n3.y,n4.y);n1.x-=normPt.x;n1.y-=normPt.y;n2.x-=normPt.x;n2.y-=normPt.y;n3.x-=normPt.x;n3.y-=normPt.y;n4.x-=normPt.x;n4.y-=normPt.y;};jsts.algorithm.RobustLineIntersector.prototype.normalizeToEnvCentre=function(n00,n01,n10,n11,normPt){var minX0=n00.xn01.x?n00.x:n01.x;var maxY0=n00.y>n01.y?n00.y:n01.y;var minX1=n10.xn11.x?n10.x:n11.x;var maxY1=n10.y>n11.y?n10.y:n11.y;var intMinX=minX0>minX1?minX0:minX1;var intMaxX=maxX0minY1?minY0:minY1;var intMaxY=maxY0=0&&orient1>=0){return Math.max(orient0,orient1);} -if(orient0<=0&&orient1<=0){return Math.max(orient0,orient1);} -return 0;};jsts.geom.LineSegment.prototype.orientationIndex2=function(p){return jsts.algorithm.CGAlgorithms.orientationIndex(this.p0,this.p1,p);};jsts.geom.LineSegment.prototype.reverse=function(){var temp=this.p0;this.p0=this.p1;this.p1=temp;};jsts.geom.LineSegment.prototype.normalize=function(){if(this.p1.compareTo(this.p0)<0)this.reverse();};jsts.geom.LineSegment.prototype.angle=function(){return Math.atan2(this.p1.y-this.p0.y,this.p1.x-this.p0.x);};jsts.geom.LineSegment.prototype.midPoint=function(){return jsts.geom.LineSegment.midPoint(this.p0,this.p1);};jsts.geom.LineSegment.prototype.distance=function(arg){if(arg instanceof jsts.geom.LineSegment){return this.distance1(arg);}else if(arg instanceof jsts.geom.Coordinate){return this.distance2(arg);}};jsts.geom.LineSegment.prototype.distance1=function(ls){return jsts.algorithm.CGAlgorithms.distanceLineLine(this.p0,this.p1,ls.p0,ls.p1);};jsts.geom.LineSegment.prototype.distance2=function(p){return jsts.algorithm.CGAlgorithms.distancePointLine(p,this.p0,this.p1);};jsts.geom.LineSegment.prototype.pointAlong=function(segmentLengthFraction){var coord=new jsts.geom.Coordinate();coord.x=this.p0.x+segmentLengthFraction*(this.p1.x-this.p0.x);coord.y=this.p0.y+segmentLengthFraction*(this.p1.y-this.p0.y);return coord;};jsts.geom.LineSegment.prototype.pointAlongOffset=function(segmentLengthFraction,offsetDistance){var segx=this.p0.x+segmentLengthFraction*(this.p1.x-this.p0.x);var segy=this.p0.y+segmentLengthFraction*(this.p1.y-this.p0.y);var dx=this.p1.x-this.p0.x;var dy=this.p1.y-this.p0.y;var len=Math.sqrt(dx*dx+dy*dy);var ux=0;var uy=0;if(offsetDistance!==0){if(len<=0){throw"Cannot compute offset from zero-length line segment";} -ux=offsetDistance*dx/len;uy=offsetDistance*dy/len;} -var offsetx=segx-uy;var offsety=segy+ux;var coord=new jsts.geom.Coordinate(offsetx,offsety);return coord;};jsts.geom.LineSegment.prototype.projectionFactor=function(p){if(p.equals(this.p0)) -return 0.0;if(p.equals(this.p1)) -return 1.0;var dx=this.p1.x-this.p0.x;var dy=this.p1.y-this.p0.y;var len2=dx*dx+dy*dy;var r=((p.x-this.p0.x)*dx+(p.y-this.p0.y)*dy)/len2;return r;};jsts.geom.LineSegment.prototype.segmentFraction=function(inputPt){var segFrac=this.projectionFactor(inputPt);if(segFrac<0){segFrac=0;}else if(segFrac>1||isNaN(segFrac)){segFrac=1;} -return segFrac;};jsts.geom.LineSegment.prototype.project=function(arg){if(arg instanceof jsts.geom.Coordinate){return this.project1(arg);}else if(arg instanceof jsts.geom.LineSegment){return this.project2(arg);}};jsts.geom.LineSegment.prototype.project1=function(p){if(p.equals(this.p0)||p.equals(this.p1)){return new jsts.geom.Coordinate(p);} -var r=this.projectionFactor(p);var coord=new jsts.geom.Coordinate();coord.x=this.p0.x+r*(this.p1.x-this.p0.x);coord.y=this.p0.y+r*(this.p1.y-this.p0.y);return coord;};jsts.geom.LineSegment.prototype.project2=function(seg){var pf0=this.projectionFactor(seg.p0);var pf1=this.projectionFactor(seg.p1);if(pf0>=1&&pf1>=1)return null;if(pf0<=0&&pf1<=0)return null;var newp0=this.project(seg.p0);if(pf0<0)newp0=p0;if(pf0>1)newp0=p1;var newp1=this.project(seg.p1);if(pf1<0.0)newp1=p0;if(pf1>1.0)newp1=p1;return new jsts.geom.LineSegment(newp0,newp1);};jsts.geom.LineSegment.prototype.closestPoint=function(p){var factor=this.projectionFactor(p);if(factor>0&&factor<1){return this.project(p);} -var dist0=this.p0.distance(p);var dist1=this.p1.distance(p);if(dist0queryChain.getId()){queryChain.computeOverlaps(testChain,overlapAction);this.nOverlaps++;} -if(this.segInt.isDone()) -return;}}};jsts.noding.MCIndexNoder.prototype.add=function(segStr){var segChains=MonotoneChainBuilder.getChains(segStr.getCoordinates(),segStr);for(var i=0;i1&&snapPts[0].equals2D(snapPts[snapPts.length-1])){distinctPtCount=snapPts.length-1;} -i=0;for(i;i=0){srcCoords.add(index+1,new jsts.geom.Coordinate(snapPt),false);}}};LineStringSnapper.prototype.findSegmentIndexToSnap=function(snapPt,srcCoords){var minDist=Number.MAX_VALUE,snapIndex=-1,i=0,dist;for(i;i0&&seqSize<4&&!this.preserveType) -return this.factory.createLineString(seq);return this.factory.createLinearRing(seq);};GeometryTransformer.prototype.transformLineString=function(geom,parent){return this.factory.createLineString(this.transformCoordinates(geom.getCoordinateSequence(),geom));};GeometryTransformer.prototype.transformMultiLineString=function(geom,parent){var transGeomList=new ArrayList();for(var i=0;isnapTolerance) -snapTolerance=fixedSnapTol;} -return snapTolerance;};GeometrySnapper.computeSizeBasedSnapTolerance=function(g){var env=g.getEnvelopeInternal();var minDimension=Math.min(env.getHeight(),env.getWidth());var snapTol=minDimension*GeometrySnapper.SNAP_PRECISION_FACTOR;return snapTol;};GeometrySnapper.computeOverlaySnapTolerance2=function(g0,g1){return Math.min(this.computeOverlaySnapTolerance(g0),this.computeOverlaySnapTolerance(g1));};GeometrySnapper.snap=function(g0,g1,snapTolerance){var snapGeom=[];var snapper0=new GeometrySnapper(g0);snapGeom[0]=snapper0.snapTo(g1,snapTolerance);var snapper1=new GeometrySnapper(g1);snapGeom[1]=snapper1.snapTo(snapGeom[0],snapTolerance);return snapGeom;};GeometrySnapper.snapToSelf=function(g0,snapTolerance,cleanResult){var snapper0=new GeometrySnapper(g0);return snapper0.snapToSelf(snapTolerance,cleanResult);};GeometrySnapper.prototype.srcGeom=null;GeometrySnapper.prototype.snapTo=function(snapGeom,snapTolerance){var snapPts=this.extractTargetCoordinates(snapGeom);var snapTrans=new SnapTransformer(snapTolerance,snapPts);return snapTrans.transform(this.srcGeom);};GeometrySnapper.prototype.snapToSelf=function(snapTolerance,cleanResult){var snapPts=this.extractTargetCoordinates(srcGeom);var snapTrans=new SnapTransformer(snapTolerance,snapPts,true);var snappedGeom=snapTrans.transform(srcGeom);var result=snappedGeom;if(cleanResult&&result instanceof Polygonal){result=snappedGeom.buffer(0);} -return result;};GeometrySnapper.prototype.extractTargetCoordinates=function(g){var ptSet=new TreeSet();var pts=g.getCoordinates();for(var i=0;i0||this.isIn) -return jsts.geom.Location.INTERIOR;return jsts.geom.Location.EXTERIOR;};jsts.algorithm.PointLocator.prototype.computeLocation=function(p,geom){if(geom instanceof jsts.geom.Point||geom instanceof jsts.geom.LineString||geom instanceof jsts.geom.Polygon){this.updateLocationInfo(this.locate(p,geom));}else if(geom instanceof jsts.geom.MultiLineString){var ml=geom;for(var i=0;i=segStr.size()-2) -return true;return false;};jsts.noding.InteriorIntersectionFinder.prototype.isDone=function(){if(this.findAllIntersections) -return false;return this.interiorIntersection!=null;};})();(function(){var RobustLineIntersector=jsts.algorithm.RobustLineIntersector;var InteriorIntersectionFinder=jsts.noding.InteriorIntersectionFinder;var MCIndexNoder=jsts.noding.MCIndexNoder;jsts.noding.FastNodingValidator=function(segStrings){this.li=new RobustLineIntersector();this.segStrings=segStrings;};jsts.noding.FastNodingValidator.prototype.li=null;jsts.noding.FastNodingValidator.prototype.segStrings=null;jsts.noding.FastNodingValidator.prototype.findAllIntersections=false;jsts.noding.FastNodingValidator.prototype.segInt=null;jsts.noding.FastNodingValidator.prototype._isValid=true;jsts.noding.FastNodingValidator.prototype.setFindAllIntersections=function(findAllIntersections){this.findAllIntersections=findAllIntersections;};jsts.noding.FastNodingValidator.prototype.getIntersections=function(){return segInt.getIntersections();};jsts.noding.FastNodingValidator.prototype.isValid=function(){this.execute();return this._isValid;};jsts.noding.FastNodingValidator.prototype.getErrorMessage=function(){if(this._isValid) -return'no intersections found';var intSegs=this.segInt.getIntersectionSegments();return'found non-noded intersection between '+ -jsts.io.WKTWriter.toLineString(intSegs[0],intSegs[1])+' and '+ -jsts.io.WKTWriter.toLineString(intSegs[2],intSegs[3]);};jsts.noding.FastNodingValidator.prototype.checkValid=function(){this.execute();if(!this._isValid) -throw new jsts.error.TopologyError(this.getErrorMessage(),this.segInt.getInteriorIntersection());};jsts.noding.FastNodingValidator.prototype.execute=function(){if(this.segInt!=null) -return;this.checkInteriorIntersections();};jsts.noding.FastNodingValidator.prototype.checkInteriorIntersections=function(){this._isValid=true;this.segInt=new InteriorIntersectionFinder(this.li);this.segInt.setFindAllIntersections(this.findAllIntersections);var noder=new MCIndexNoder();noder.setSegmentIntersector(this.segInt);noder.computeNodes(this.segStrings);if(this.segInt.hasIntersection()){this._isValid=false;return;}};})();(function(){jsts.noding.BasicSegmentString=function(pts,data){this.pts=pts;this.data=data;};jsts.noding.BasicSegmentString.prototype=new jsts.noding.SegmentString();jsts.noding.BasicSegmentString.prototype.pts=null;jsts.noding.BasicSegmentString.prototype.data=null;jsts.noding.BasicSegmentString.prototype.getData=function(){return this.data;} -jsts.noding.BasicSegmentString.prototype.setData=function(data){this.data=data;};jsts.noding.BasicSegmentString.prototype.size=function(){return this.pts.length;};jsts.noding.BasicSegmentString.prototype.getCoordinate=function(i){return this.pts[i];};jsts.noding.BasicSegmentString.prototype.getCoordinates=function(){return this.pts;};jsts.noding.BasicSegmentString.prototype.isClosed=function(){return this.pts[0].equals(this.pts[this.pts.length-1]);};jsts.noding.BasicSegmentString.prototype.getSegmentOctant=function(index){if(index==this.pts.length-1) -return-1;return jsts.noding.Octant.octant(this.getCoordinate(index),this.getCoordinate(index+1));};})();(function(){var FastNodingValidator=jsts.noding.FastNodingValidator;var BasicSegmentString=jsts.noding.BasicSegmentString;var ArrayList=javascript.util.ArrayList;jsts.geomgraph.EdgeNodingValidator=function(edges){this.nv=new FastNodingValidator(jsts.geomgraph.EdgeNodingValidator.toSegmentStrings(edges));};jsts.geomgraph.EdgeNodingValidator.checkValid=function(edges){var validator=new jsts.geomgraph.EdgeNodingValidator(edges);validator.checkValid();};jsts.geomgraph.EdgeNodingValidator.toSegmentStrings=function(edges){var segStrings=new ArrayList();for(var i=edges.iterator();i.hasNext();){var e=i.next();segStrings.add(new BasicSegmentString(e.getCoordinates(),e));} -return segStrings;};jsts.geomgraph.EdgeNodingValidator.prototype.nv=null;jsts.geomgraph.EdgeNodingValidator.prototype.checkValid=function(){this.nv.checkValid();};})();jsts.operation.GeometryGraphOperation=function(g0,g1,boundaryNodeRule){this.li=new jsts.algorithm.RobustLineIntersector();this.arg=[];if(g0===undefined){return;} -if(g1===undefined){this.setComputationPrecision(g0.getPrecisionModel());this.arg[0]=new jsts.geomgraph.GeometryGraph(0,g0);return;} -boundaryNodeRule=boundaryNodeRule||jsts.algorithm.BoundaryNodeRule.OGC_SFS_BOUNDARY_RULE;if(g0.getPrecisionModel().compareTo(g1.getPrecisionModel())>=0) -this.setComputationPrecision(g0.getPrecisionModel());else -this.setComputationPrecision(g1.getPrecisionModel());this.arg[0]=new jsts.geomgraph.GeometryGraph(0,g0,boundaryNodeRule);this.arg[1]=new jsts.geomgraph.GeometryGraph(1,g1,boundaryNodeRule);};jsts.operation.GeometryGraphOperation.prototype.li=null;jsts.operation.GeometryGraphOperation.prototype.resultPrecisionModel=null;jsts.operation.GeometryGraphOperation.prototype.arg=null;jsts.operation.GeometryGraphOperation.prototype.getArgGeometry=function(i){return arg[i].getGeometry();};jsts.operation.GeometryGraphOperation.prototype.setComputationPrecision=function(pm){this.resultPrecisionModel=pm;this.li.setPrecisionModel(this.resultPrecisionModel);};jsts.operation.overlay.OverlayNodeFactory=function(){};jsts.operation.overlay.OverlayNodeFactory.prototype=new jsts.geomgraph.NodeFactory();jsts.operation.overlay.OverlayNodeFactory.constructor=jsts.operation.overlay.OverlayNodeFactory;jsts.operation.overlay.OverlayNodeFactory.prototype.createNode=function(coord){return new jsts.geomgraph.Node(coord,new jsts.geomgraph.DirectedEdgeStar());};jsts.operation.overlay.PolygonBuilder=function(geometryFactory){this.shellList=[];this.geometryFactory=geometryFactory;};jsts.operation.overlay.PolygonBuilder.prototype.geometryFactory=null;jsts.operation.overlay.PolygonBuilder.prototype.shellList=null;jsts.operation.overlay.PolygonBuilder.prototype.add=function(graph){if(arguments.length===2){this.add2.apply(this,arguments);return;} -this.add2(graph.getEdgeEnds(),graph.getNodes());};jsts.operation.overlay.PolygonBuilder.prototype.add2=function(dirEdges,nodes){jsts.geomgraph.PlanarGraph.linkResultDirectedEdges(nodes);var maxEdgeRings=this.buildMaximalEdgeRings(dirEdges);var freeHoleList=[];var edgeRings=this.buildMinimalEdgeRings(maxEdgeRings,this.shellList,freeHoleList);this.sortShellsAndHoles(edgeRings,this.shellList,freeHoleList);this.placeFreeHoles(this.shellList,freeHoleList);};jsts.operation.overlay.PolygonBuilder.prototype.getPolygons=function(){var resultPolyList=this.computePolygons(this.shellList);return resultPolyList;};jsts.operation.overlay.PolygonBuilder.prototype.buildMaximalEdgeRings=function(dirEdges){var maxEdgeRings=[];for(var it=dirEdges.iterator();it.hasNext();){var de=it.next();if(de.isInResult()&&de.getLabel().isArea()){if(de.getEdgeRing()==null){var er=new jsts.operation.overlay.MaximalEdgeRing(de,this.geometryFactory);maxEdgeRings.push(er);er.setInResult();}}} -return maxEdgeRings;};jsts.operation.overlay.PolygonBuilder.prototype.buildMinimalEdgeRings=function(maxEdgeRings,shellList,freeHoleList){var edgeRings=[];for(var i=0;i2){er.linkDirectedEdgesForMinimalEdgeRings();var minEdgeRings=er.buildMinimalRings();var shell=this.findShell(minEdgeRings);if(shell!==null){this.placePolygonHoles(shell,minEdgeRings);shellList.push(shell);}else{freeHoleList=freeHoleList.concat(minEdgeRings);}}else{edgeRings.push(er);}} -return edgeRings;};jsts.operation.overlay.PolygonBuilder.prototype.findShell=function(minEdgeRings){var shellCount=0;var shell=null;for(var i=0;i=0;i--){var nextOut=this.resultAreaEdgeList.get(i);var nextIn=nextOut.getSym();if(firstOut===null&&nextOut.getEdgeRing()===er) -firstOut=nextOut;switch(state){case this.SCANNING_FOR_INCOMING:if(nextIn.getEdgeRing()!=er) -continue;incoming=nextIn;state=this.LINKING_TO_OUTGOING;break;case this.LINKING_TO_OUTGOING:if(nextOut.getEdgeRing()!==er) -continue;incoming.setNextMin(nextOut);state=this.SCANNING_FOR_INCOMING;break;}} -if(state===this.LINKING_TO_OUTGOING){Assert.isTrue(firstOut!==null,'found null for first outgoing dirEdge');Assert.isTrue(firstOut.getEdgeRing()===er,'unable to link last incoming dirEdge');incoming.setNextMin(firstOut);}};jsts.geomgraph.DirectedEdgeStar.prototype.linkAllDirectedEdges=function(){this.getEdges();var prevOut=null;var firstIn=null;for(var i=this.edgeList.size()-1;i>=0;i--){var nextOut=this.edgeList.get(i);var nextIn=nextOut.getSym();if(firstIn===null) -firstIn=nextIn;if(prevOut!==null) -nextIn.setNext(prevOut);prevOut=nextOut;} -firstIn.setNext(prevOut);};jsts.geomgraph.DirectedEdgeStar.prototype.findCoveredLineEdges=function(){var startLoc=Location.NONE;for(var it=this.iterator();it.hasNext();){var nextOut=it.next();var nextIn=nextOut.getSym();if(!nextOut.isLineEdge()){if(nextOut.isInResult()){startLoc=Location.INTERIOR;break;} -if(nextIn.isInResult()){startLoc=Location.EXTERIOR;break;}}} -if(startLoc===Location.NONE) -return;var currLoc=startLoc;for(var it=this.iterator();it.hasNext();){var nextOut=it.next();var nextIn=nextOut.getSym();if(nextOut.isLineEdge()){nextOut.getEdge().setCovered(currLoc===Location.INTERIOR);}else{if(nextOut.isInResult()) -currLoc=Location.EXTERIOR;if(nextIn.isInResult()) -currLoc=Location.INTERIOR;}}};jsts.geomgraph.DirectedEdgeStar.prototype.computeDepths=function(de){if(arguments.length===2){this.computeDepths2.apply(this,arguments);return;} -var edgeIndex=this.findIndex(de);var label=de.getLabel();var startDepth=de.getDepth(Position.LEFT);var targetLastDepth=de.getDepth(Position.RIGHT);var nextDepth=this.computeDepths2(edgeIndex+1,this.edgeList.size(),startDepth);var lastDepth=this.computeDepths2(0,edgeIndex,nextDepth);if(lastDepth!=targetLastDepth) -throw new jsts.error.TopologyError('depth mismatch at '+ -de.getCoordinate());};jsts.geomgraph.DirectedEdgeStar.prototype.computeDepths2=function(startIndex,endIndex,startDepth){var currDepth=startDepth;for(var i=startIndex;i0){return this.pts[0];}else{return null;}} -return this.pts[i];};jsts.geomgraph.Edge.prototype.isClosed=function(){return this.pts[0].equals(this.pts[this.pts.length-1]);};jsts.geomgraph.Edge.prototype.setIsolated=function(isIsolated){this._isIsolated=isIsolated;};jsts.geomgraph.Edge.prototype.isIsolated=function(){return this._isIsolated;};jsts.geomgraph.Edge.prototype.addIntersections=function(li,segmentIndex,geomIndex){for(var i=0;i=0){if(dy>=0){if(adx>=ady) -return 0;else -return 1;} -else{if(adx>=ady) -return 7;else -return 6;}} -else{if(dy>=0){if(adx>=ady) -return 3;else -return 2;} -else{if(adx>=ady) -return 4;else -return 5;}}};jsts.noding.Octant.octant2=function(p0,p1){var dx=p1.x-p0.x;var dy=p1.y-p0.y;if(dx===0.0&&dy===0.0) -throw new jsts.error.IllegalArgumentError('Cannot compute the octant for two identical points '+p0);return jsts.noding.Octant.octant(dx,dy);};jsts.operation.union.UnionInteracting=function(g0,g1){this.g0=g0;this.g1=g1;this.geomFactory=g0.getFactory();this.interacts0=[];this.interacts1=[];};jsts.operation.union.UnionInteracting.union=function(g0,g1){var uue=new jsts.operation.union.UnionInteracting(g0,g1);return uue.union();};jsts.operation.union.UnionInteracting.prototype.geomFactory=null;jsts.operation.union.UnionInteracting.prototype.g0=null;jsts.operation.union.UnionInteracting.prototype.g1=null;jsts.operation.union.UnionInteracting.prototype.interacts0=null;jsts.operation.union.UnionInteracting.prototype.interacts1=null;jsts.operation.union.UnionInteracting.prototype.union=function(){this.computeInteracting();var int0=this.extractElements(this.g0,this.interacts0,true);var int1=this.extractElements(this.g1,this.interacts1,true);if(int0.isEmpty()||int1.isEmpty()){} -var union=in0.union(int1);var disjoint0=this.extractElements(this.g0,this.interacts0,false);var disjoint1=this.extractElements(this.g1,this.interacts1,false);var overallUnion=jsts.geom.util.GeometryCombiner.combine(union,disjoint0,disjoint1);return overallUnion;};jsts.operation.union.UnionInteracting.prototype.bufferUnion=function(g0,g1){var factory=g0.getFactory();var gColl=factory.createGeometryCollection([g0,g1]);var unionAll=gColl.buffer(0.0);return unionAll;};jsts.operation.union.UnionInteracting.prototype.computeInteracting=function(elem0){if(!elem0){for(var i=0,l=this.g0.getNumGeometries();i0;return isInCircle;};jsts.triangulate.quadedge.TrianglePredicate.isInCircleNormalized=function(a,b,c,p){var adx,ady,bdx,bdy,cdx,cdy,abdet,bcdet,cadet,alift,blift,clift,disc;adx=a.x-p.x;ady=a.y-p.y;bdx=b.x-p.x;bdy=b.y-p.y;cdx=c.x-p.x;cdy=c.y-p.y;abdet=adx*bdy-bdx*ady;bcdet=bdx*cdy-cdx*bdy;cadet=cdx*ady-adx*cdy;alift=adx*adx+ady*ady;blift=bdx*bdx+bdy*bdy;clift=cdx*cdx+cdy*cdy;disc=alift*bcdet+blift*cadet+clift*abdet;return disc>0;};jsts.triangulate.quadedge.TrianglePredicate.triArea=function(a,b,c){return(b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);};jsts.triangulate.quadedge.TrianglePredicate.isInCircleRobust=function(a,b,c,p){return jsts.triangulate.quadedge.TrianglePredicate.isInCircleNormalized(a,b,c,p);};jsts.triangulate.quadedge.TrianglePredicate.isInCircleDDSlow=function(a,b,c,p){var px,py,ax,ay,bx,by,cx,cy,aTerm,bTerm,cTerm,pTerm,sum,isInCircle;px=jsts.math.DD.valueOf(p.x);py=jsts.math.DD.valueOf(p.y);ax=jsts.math.DD.valueOf(a.x);ay=jsts.math.DD.valueOf(a.y);bx=jsts.math.DD.valueOf(b.x);by=jsts.math.DD.valueOf(b.y);cx=jsts.math.DD.valueOf(c.x);cy=jsts.math.DD.valueOf(c.y);aTerm=(ax.multiply(ax).add(ay.multiply(ay))).multiply(jsts.triangulate.quadedge.TrianglePredicate.triAreaDDSlow(bx,by,cx,cy,px,py));bTerm=(bx.multiply(bx).add(by.multiply(by))).multiply(jsts.triangulate.quadedge.TrianglePredicate.triAreaDDSlow(ax,ay,cx,cy,px,py));cTerm=(cx.multiply(cx).add(cy.multiply(cy))).multiply(jsts.triangulate.quadedge.TrianglePredicate.triAreaDDSlow(ax,ay,bx,by,px,py));pTerm=(px.multiply(px).add(py.multiply(py))).multiply(jsts.triangulate.quadedge.TrianglePredicate.triAreaDDSlow(ax,ay,bx,by,cx,cy));sum=aTerm.subtract(bTerm).add(cTerm).subtract(pTerm);isInCircle=sum.doubleValue()>0;return isInCircle;};jsts.triangulate.quadedge.TrianglePredicate.triAreaDDSlow=function(ax,ay,bx,by,cx,cy){return(bx.subtract(ax).multiply(cy.subtract(ay)).subtract(by.subtract(ay).multiply(cx.subtract(ax))));};jsts.triangulate.quadedge.TrianglePredicate.isInCircleDDFast=function(a,b,c,p){var aTerm,bTerm,cTerm,pTerm,sum,isInCircle;aTerm=(jsts.math.DD.sqr(a.x).selfAdd(jsts.math.DD.sqr(a.y))).selfMultiply(jsts.triangulate.quadedge.TrianglePredicate.triAreaDDFast(b,c,p));bTerm=(jsts.math.DD.sqr(b.x).selfAdd(jsts.math.DD.sqr(b.y))).selfMultiply(jsts.triangulate.quadedge.TrianglePredicate.triAreaDDFast(a,c,p));cTerm=(jsts.math.DD.sqr(c.x).selfAdd(jsts.math.DD.sqr(c.y))).selfMultiply(jsts.triangulate.quadedge.TrianglePredicate.triAreaDDFast(a,b,p));pTerm=(jsts.math.DD.sqr(p.x).selfAdd(jsts.math.DD.sqr(p.y))).selfMultiply(jsts.triangulate.quadedge.TrianglePredicate.triAreaDDFast(a,b,c));sum=aTerm.selfSubtract(bTerm).selfAdd(cTerm).selfSubtract(pTerm);isInCircle=sum.doubleValue()>0;return isInCircle;};jsts.triangulate.quadedge.TrianglePredicate.triAreaDDFast=function(a,b,c){var t1,t2;t1=jsts.math.DD.valueOf(b.x).selfSubtract(a.x).selfMultiply(jsts.math.DD.valueOf(c.y).selfSubtract(a.y));t2=jsts.math.DD.valueOf(b.y).selSubtract(a.y).selfMultiply(jsts.math.DD.valueOf(c.x).selfSubtract(a.x));return t1.selfSubtract(t2);};jsts.triangulate.quadedge.TrianglePredicate.isInCircleDDNormalized=function(a,b,c,p){var adx,ady,bdx,bdy,cdx,cdy,abdet,bcdet,cadet,alift,blift,clift,sum,isInCircle;adx=jsts.math.DD.valueOf(a.x).selfSubtract(p.x);ady=jsts.math.DD.valueOf(a.y).selfSubtract(p.y);bdx=jsts.math.DD.valueOf(b.x).selfSubtract(p.x);bdx=jsts.math.DD.valueOf(b.y).selfSubtract(p.y);cdx=jsts.math.DD.valueOf(c.x).selfSubtract(p.x);cdx=jsts.math.DD.valueOf(c.y).selfSubtract(p.y);abdet=adx.multiply(bdy).selfSubtract(bdx.multiply(ady));bcdet=bdx.multiply(cdy).selfSubtract(cdx.multiply(bdy));cadet=cdx.multiply(ady).selfSubtract(adx.multiply(cdy));alift=adx.multiply(adx).selfAdd(ady.multiply(ady));blift=bdx.multiply(bdx).selfAdd(bdy.multiply(bdy));clift=cdx.multiply(cdx).selfAdd(cdy.multiply(cdy));sum=alift.selfMultiply(bcdet).selfAdd(blift.selfMultiply(cadet)).selfAdd(clift.selfMultiply(abdet));isInCircle=sum.doubleValue()>0;return isInCircle;};jsts.triangulate.quadedge.TrianglePredicate.isInCircleCC=function(a,b,c,p){var cc,ccRadius,pRadiusDiff;cc=jsts.geom.Triangle.circumcentre(a,b,c);ccRadius=a.distance(cc);pRadiusDiff=p.distance(cc)-ccRadius;return pRadiusDiff<=0;};jsts.operation.union.PointGeometryUnion=function(pointGeom,otherGeom){this.pointGeom=pointGeom;this.otherGeom=otherGeom;this.geomFact=otherGeom.getFactory();};jsts.operation.union.PointGeometryUnion.union=function(pointGeom,otherGeom){var unioner=new jsts.operation.union.PointGeometryUnion(pointGeom,otherGeom);return unioner.union();};jsts.operation.union.PointGeometryUnion.prototype.pointGeom=null;jsts.operation.union.PointGeometryUnion.prototype.otherGeom=null;jsts.operation.union.PointGeometryUnion.prototype.geomFact=null;jsts.operation.union.PointGeometryUnion.prototype.union=function(){var locator=new jsts.algorithm.PointLocator();var exteriorCoords=[];for(var i=0,l=this.pointGeom.getNumGeometries();i0)&&(y2<=0))||((y2>0)&&(y1<=0))){xInt=jsts.algorithm.RobustDeterminant.signOfDet2x2(x1,y1,x2,y2)/(y2-y1);if(0.0max){this.min=max;this.max=min;}};Interval.prototype.getMin=function(){return this.min;};Interval.prototype.getMax=function(){return this.max;};Interval.prototype.getWidth=function(){return(this.max-this.min);};Interval.prototype.expandToInclude=function(interval){if(interval.max>this.max){this.max=interval.max;} -if(interval.minmax||this.max=this.min&&max<=this.max);};Interval.prototype.containsPoint=function(p){return(p>=this.min&&p<=this.max);};jsts.index.bintree.Interval=Interval;})();jsts.index.DoubleBits=function(){};jsts.index.DoubleBits.powerOf2=function(exp){return Math.pow(2,exp);};jsts.index.DoubleBits.exponent=function(d){return jsts.index.DoubleBits.CVTFWD(64,d)-1023;};jsts.index.DoubleBits.CVTFWD=function(NumW,Qty){var Sign,Expo,Mant,Bin,nb01='';var Inf={32:{d:0x7F,c:0x80,b:0,a:0},64:{d:0x7FF0,c:0,b:0,a:0}};var ExW={32:8,64:11}[NumW],MtW=NumW-ExW-1;if(!Bin){Sign=Qty<0||1/Qty<0;if(!isFinite(Qty)){Bin=Inf[NumW];if(Sign){Bin.d+=1<<(NumW/4-1);} -Expo=Math.pow(2,ExW)-1;Mant=0;}} -if(!Bin){Expo={32:127,64:1023}[NumW];Mant=Math.abs(Qty);while(Mant>=2){Expo++;Mant/=2;} -while(Mant<1&&Expo>0){Expo--;Mant*=2;} -if(Expo<=0){Mant/=2;nb01='Zero or Denormal';} -if(NumW===32&&Expo>254){nb01='Too big for Single';Bin={d:Sign?0xFF:0x7F,c:0x80,b:0,a:0};Expo=Math.pow(2,ExW)-1;Mant=0;}} -return Expo;};(function(){var DoubleBits=jsts.index.DoubleBits;var Interval=jsts.index.bintree.Interval;var Key=function(interval){this.pt=0.0;this.level=0;this.computeKey(interval);};Key.computeLevel=function(interval){var dx=interval.getWidth(),level;level=DoubleBits.exponent(dx)+1;return level;};Key.prototype.getPoint=function(){return this.pt;};Key.prototype.getLevel=function(){return this.level;};Key.prototype.getInterval=function(){return this.interval;};Key.prototype.computeKey=function(itemInterval){this.level=Key.computeLevel(itemInterval);this.interval=new Interval();this.computeInterval(this.level,itemInterval);while(!this.interval.contains(itemInterval)){this.level+=1;this.computeInterval(this.level,itemInterval);}};Key.prototype.computeInterval=function(level,itemInterval){var size=DoubleBits.powerOf2(level);this.pt=Math.floor(itemInterval.getMin()/size)*size;this.interval.init(this.pt,this.pt+size);};jsts.index.bintree.Key=Key;})();jsts.operation.buffer.SubgraphDepthLocater=function(subgraphs){this.subgraphs=[];this.seg=new jsts.geom.LineSegment();this.subgraphs=subgraphs;};jsts.operation.buffer.SubgraphDepthLocater.prototype.subgraphs=null;jsts.operation.buffer.SubgraphDepthLocater.prototype.seg=null;jsts.operation.buffer.SubgraphDepthLocater.prototype.getDepth=function(p){var stabbedSegments=this.findStabbedSegments(p);if(stabbedSegments.length===0) -return 0;stabbedSegments.sort();var ds=stabbedSegments[0];return ds.leftDepth;};jsts.operation.buffer.SubgraphDepthLocater.prototype.findStabbedSegments=function(stabbingRayLeftPt){if(arguments.length===3){this.findStabbedSegments2.apply(this,arguments);return;} -var stabbedSegments=[];for(var i=0;ienv.getMaxY()) -continue;this.findStabbedSegments2(stabbingRayLeftPt,bsg.getDirectedEdges(),stabbedSegments);} -return stabbedSegments;};jsts.operation.buffer.SubgraphDepthLocater.prototype.findStabbedSegments2=function(stabbingRayLeftPt,dirEdges,stabbedSegments){if(arguments[1]instanceof jsts.geomgraph.DirectedEdge){this.findStabbedSegments3(stabbingRayLeftPt,dirEdges,stabbedSegments);return;} -for(var i=dirEdges.iterator();i.hasNext();){var de=i.next();if(!de.isForward()) -continue;this.findStabbedSegments3(stabbingRayLeftPt,de,stabbedSegments);}};jsts.operation.buffer.SubgraphDepthLocater.prototype.findStabbedSegments3=function(stabbingRayLeftPt,dirEdge,stabbedSegments){var pts=dirEdge.getEdge().getCoordinates();for(var i=0;ithis.seg.p1.y) -this.seg.reverse();var maxx=Math.max(this.seg.p0.x,this.seg.p1.x);if(maxxthis.seg.p1.y) -continue;if(jsts.algorithm.CGAlgorithms.computeOrientation(this.seg.p0,this.seg.p1,stabbingRayLeftPt)===jsts.algorithm.CGAlgorithms.RIGHT) -continue;var depth=dirEdge.getDepth(jsts.geomgraph.Position.LEFT);if(!this.seg.p0.equals(pts[i])) -depth=dirEdge.getDepth(jsts.geomgraph.Position.RIGHT);var ds=new jsts.operation.buffer.SubgraphDepthLocater.DepthSegment(this.seg,depth);stabbedSegments.push(ds);}};jsts.operation.buffer.SubgraphDepthLocater.DepthSegment=function(seg,depth){this.upwardSeg=new jsts.geom.LineSegment(seg);this.leftDepth=depth;};jsts.operation.buffer.SubgraphDepthLocater.DepthSegment.prototype.upwardSeg=null;jsts.operation.buffer.SubgraphDepthLocater.DepthSegment.prototype.leftDepth=null;jsts.operation.buffer.SubgraphDepthLocater.DepthSegment.prototype.compareTo=function(obj){var other=obj;var orientIndex=this.upwardSeg.orientationIndex(other.upwardSeg);if(orientIndex===0) -orientIndex=-1*other.upwardSeg.orientationIndex(upwardSeg);if(orientIndex!==0) -return orientIndex;return this.compareX(this.upwardSeg,other.upwardSeg);};jsts.operation.buffer.SubgraphDepthLocater.DepthSegment.prototype.compareX=function(seg0,seg1){var compare0=seg0.p0.compareTo(seg1.p0);if(compare0!==0) -return compare0;return seg0.p1.compareTo(seg1.p1);};jsts.noding.snapround.HotPixel=function(pt,scaleFactor,li){this.corner=[];this.originalPt=pt;this.pt=pt;this.scaleFactor=scaleFactor;this.li=li;if(this.scaleFactor!==1.0){this.pt=new jsts.geom.Coordinate(this.scale(pt.x),this.scale(pt.y));this.p0Scaled=new jsts.geom.Coordinate();this.p1Scaled=new jsts.geom.Coordinate();} -this.initCorners(this.pt);};jsts.noding.snapround.HotPixel.prototype.li=null;jsts.noding.snapround.HotPixel.prototype.pt=null;jsts.noding.snapround.HotPixel.prototype.originalPt=null;jsts.noding.snapround.HotPixel.prototype.ptScaled=null;jsts.noding.snapround.HotPixel.prototype.p0Scaled=null;jsts.noding.snapround.HotPixel.prototype.p1Scaled=null;jsts.noding.snapround.HotPixel.prototype.scaleFactor=undefined;jsts.noding.snapround.HotPixel.prototype.minx=undefined;jsts.noding.snapround.HotPixel.prototype.maxx=undefined;jsts.noding.snapround.HotPixel.prototype.miny=undefined;jsts.noding.snapround.HotPixel.prototype.maxy=undefined;jsts.noding.snapround.HotPixel.prototype.corner=null;jsts.noding.snapround.HotPixel.prototype.safeEnv=null;jsts.noding.snapround.HotPixel.prototype.getCoordinate=function(){return this.originalPt;};jsts.noding.snapround.HotPixel.SAFE_ENV_EXPANSION_FACTOR=0.75;jsts.noding.snapround.HotPixel.prototype.getSafeEnvelope=function(){if(this.safeEnv===null){var safeTolerance=jsts.noding.snapround.HotPixel.SAFE_ENV_EXPANSION_FACTOR/this.scaleFactor;this.safeEnv=new jsts.geom.Envelope(this.originalPt.x-safeTolerance,this.originalPt.x+safeTolerance,this.originalPt.y-safeTolerance,this.originalPt.y+safeTolerance);} -return this.safeEnv;};jsts.noding.snapround.HotPixel.prototype.initCorners=function(pt){var tolerance=0.5;this.minx=pt.x-tolerance;this.maxx=pt.x+tolerance;this.miny=pt.y-tolerance;this.maxy=pt.y+tolerance;this.corner[0]=new jsts.geom.Coordinate(this.maxx,this.maxy);this.corner[1]=new jsts.geom.Coordinate(this.minx,this.maxy);this.corner[2]=new jsts.geom.Coordinate(this.minx,this.miny);this.corner[3]=new jsts.geom.Coordinate(this.maxx,this.miny);};jsts.noding.snapround.HotPixel.prototype.scale=function(val){return Math.round(val*this.scaleFactor);};jsts.noding.snapround.HotPixel.prototype.intersects=function(p0,p1){if(this.scaleFactor===1.0) -return this.intersectsScaled(p0,p1);this.copyScaled(p0,this.p0Scaled);this.copyScaled(p1,this.p1Scaled);return this.intersectsScaled(this.p0Scaled,this.p1Scaled);};jsts.noding.snapround.HotPixel.prototype.copyScaled=function(p,pScaled){pScaled.x=this.scale(p.x);pScaled.y=this.scale(p.y);};jsts.noding.snapround.HotPixel.prototype.intersectsScaled=function(p0,p1){var segMinx=Math.min(p0.x,p1.x);var segMaxx=Math.max(p0.x,p1.x);var segMiny=Math.min(p0.y,p1.y);var segMaxy=Math.max(p0.y,p1.y);var isOutsidePixelEnv=this.maxxsegMaxx||this.maxysegMaxy;if(isOutsidePixelEnv) -return false;var intersects=this.intersectsToleranceSquare(p0,p1);jsts.util.Assert.isTrue(!(isOutsidePixelEnv&&intersects),'Found bad envelope test');return intersects;};jsts.noding.snapround.HotPixel.prototype.intersectsToleranceSquare=function(p0,p1){var intersectsLeft=false;var intersectsBottom=false;this.li.computeIntersection(p0,p1,this.corner[0],this.corner[1]);if(this.li.isProper()) -return true;this.li.computeIntersection(p0,p1,this.corner[1],this.corner[2]);if(this.li.isProper()) -return true;if(this.li.hasIntersection()) -intersectsLeft=true;this.li.computeIntersection(p0,p1,this.corner[2],this.corner[3]);if(this.li.isProper()) -return true;if(this.li.hasIntersection()) -intersectsBottom=true;this.li.computeIntersection(p0,p1,this.corner[3],this.corner[0]);if(this.li.isProper()) -return true;if(intersectsLeft&&intersectsBottom) -return true;if(p0.equals(this.pt)) -return true;if(p1.equals(this.pt)) -return true;return false;};jsts.noding.snapround.HotPixel.prototype.intersectsPixelClosure=function(p0,p1){this.li.computeIntersection(p0,p1,this.corner[0],this.corner[1]);if(this.li.hasIntersection()) -return true;this.li.computeIntersection(p0,p1,this.corner[1],this.corner[2]);if(this.li.hasIntersection()) -return true;this.li.computeIntersection(p0,p1,this.corner[2],this.corner[3]);if(this.li.hasIntersection()) -return true;this.li.computeIntersection(p0,p1,this.corner[3],this.corner[0]);if(this.li.hasIntersection()) -return true;return false;};jsts.noding.snapround.HotPixel.prototype.addSnappedNode=function(segStr,segIndex){var p0=segStr.getCoordinate(segIndex);var p1=segStr.getCoordinate(segIndex+1);if(this.intersects(p0,p1)){segStr.addIntersection(this.getCoordinate(),segIndex);return true;} -return false;};jsts.operation.buffer.BufferInputLineSimplifier=function(inputLine){this.inputLine=inputLine;};jsts.operation.buffer.BufferInputLineSimplifier.simplify=function(inputLine,distanceTol){var simp=new jsts.operation.buffer.BufferInputLineSimplifier(inputLine);return simp.simplify(distanceTol);};jsts.operation.buffer.BufferInputLineSimplifier.INIT=0;jsts.operation.buffer.BufferInputLineSimplifier.DELETE=1;jsts.operation.buffer.BufferInputLineSimplifier.KEEP=1;jsts.operation.buffer.BufferInputLineSimplifier.prototype.inputLine=null;jsts.operation.buffer.BufferInputLineSimplifier.prototype.distanceTol=null;jsts.operation.buffer.BufferInputLineSimplifier.prototype.isDeleted=null;jsts.operation.buffer.BufferInputLineSimplifier.prototype.angleOrientation=jsts.algorithm.CGAlgorithms.COUNTERCLOCKWISE;jsts.operation.buffer.BufferInputLineSimplifier.prototype.simplify=function(distanceTol){this.distanceTol=Math.abs(distanceTol);if(distanceTol<0) -this.angleOrientation=jsts.algorithm.CGAlgorithms.CLOCKWISE;this.isDeleted=[];this.isDeleted.length=this.inputLine.length;var isChanged=false;do{isChanged=this.deleteShallowConcavities();}while(isChanged);return this.collapseLine();};jsts.operation.buffer.BufferInputLineSimplifier.prototype.deleteShallowConcavities=function(){var index=1;var maxIndex=this.inputLine.length-1;var midIndex=this.findNextNonDeletedIndex(index);var lastIndex=this.findNextNonDeletedIndex(midIndex);var isChanged=false;while(lastIndexpe.xValue){return 1;} -if(this.eventTypepe.eventType){return 1;} -return 0;};jsts.geom.CoordinateList=function(coord,allowRepeated){this.array=[];allowRepeated=(allowRepeated===undefined)?true:allowRepeated;if(coord!==undefined){this.add(coord,allowRepeated);}};jsts.geom.CoordinateList.prototype=new javascript.util.ArrayList();jsts.geom.CoordinateList.prototype.iterator=null;jsts.geom.CoordinateList.prototype.remove=null;jsts.geom.CoordinateList.prototype.get=function(i){return this.array[i];};jsts.geom.CoordinateList.prototype.set=function(i,e){var o=this.array[i];this.array[i]=e;return o;};jsts.geom.CoordinateList.prototype.size=function(){return this.array.length;};jsts.geom.CoordinateList.prototype.add=function(){if(arguments.length>1){return this.addCoordinates.apply(this,arguments);}else{return this.array.push(arguments[0]);}};jsts.geom.CoordinateList.prototype.addCoordinates=function(coord,allowRepeated,direction){if(coord instanceof jsts.geom.Coordinate){return this.addCoordinate.apply(this,arguments);}else if(typeof coord==='number'){return this.insertCoordinate.apply(this,arguments);} -direction=direction||true;if(direction){for(var i=0;i=0;i--){this.addCoordinate(coord[i],allowRepeated);}} -return true;};jsts.geom.CoordinateList.prototype.addCoordinate=function(coord,allowRepeated){if(!allowRepeated){if(this.size()>=1){var last=this.get(this.size()-1);if(last.equals2D(coord))return;}} -this.add(coord);};jsts.geom.CoordinateList.prototype.insertCoordinate=function(index,coord,allowRepeated){if(!allowRepeated){var before=index>0?index-1:-1;if(before!==-1&&this.get(before).equals2D(coord)){return;} -var after=index0){this.addCoordinate(new jsts.geom.Coordinate(this.get(0)),false);}};jsts.geom.CoordinateList.prototype.toArray=function(){return this.array;};jsts.geom.CoordinateList.prototype.toCoordinateArray=function(){return this.array;};jsts.operation.buffer.OffsetSegmentGenerator=function(precisionModel,bufParams,distance){this.seg0=new jsts.geom.LineSegment();this.seg1=new jsts.geom.LineSegment();this.offset0=new jsts.geom.LineSegment();this.offset1=new jsts.geom.LineSegment();this.precisionModel=precisionModel;this.bufParams=bufParams;this.li=new jsts.algorithm.RobustLineIntersector();this.filletAngleQuantum=Math.PI/2.0/bufParams.getQuadrantSegments();if(this.bufParams.getQuadrantSegments()>=8&&this.bufParams.getJoinStyle()===jsts.operation.buffer.BufferParameters.JOIN_ROUND){this.closingSegLengthFactor=jsts.operation.buffer.OffsetSegmentGenerator.MAX_CLOSING_SEG_LEN_FACTOR;} -this.init(distance);};jsts.operation.buffer.OffsetSegmentGenerator.OFFSET_SEGMENT_SEPARATION_FACTOR=1.0E-3;jsts.operation.buffer.OffsetSegmentGenerator.INSIDE_TURN_VERTEX_SNAP_DISTANCE_FACTOR=1.0E-3;jsts.operation.buffer.OffsetSegmentGenerator.CURVE_VERTEX_SNAP_DISTANCE_FACTOR=1.0E-6;jsts.operation.buffer.OffsetSegmentGenerator.MAX_CLOSING_SEG_LEN_FACTOR=80;jsts.operation.buffer.OffsetSegmentGenerator.prototype.maxCurveSegmentError=0.0;jsts.operation.buffer.OffsetSegmentGenerator.prototype.filletAngleQuantum=null;jsts.operation.buffer.OffsetSegmentGenerator.prototype.closingSegLengthFactor=1;jsts.operation.buffer.OffsetSegmentGenerator.prototype.segList=null;jsts.operation.buffer.OffsetSegmentGenerator.prototype.distance=0.0;jsts.operation.buffer.OffsetSegmentGenerator.prototype.precisionModel=null;jsts.operation.buffer.OffsetSegmentGenerator.prototype.bufParams=null;jsts.operation.buffer.OffsetSegmentGenerator.prototype.li=null;jsts.operation.buffer.OffsetSegmentGenerator.prototype.s0=null;jsts.operation.buffer.OffsetSegmentGenerator.prototype.s1=null;jsts.operation.buffer.OffsetSegmentGenerator.prototype.s2=null;jsts.operation.buffer.OffsetSegmentGenerator.prototype.seg0=null;jsts.operation.buffer.OffsetSegmentGenerator.prototype.seg1=null;jsts.operation.buffer.OffsetSegmentGenerator.prototype.offset0=null;jsts.operation.buffer.OffsetSegmentGenerator.prototype.offset1=null;jsts.operation.buffer.OffsetSegmentGenerator.prototype.side=0;jsts.operation.buffer.OffsetSegmentGenerator.prototype.hasNarrowConcaveAngle=false;jsts.operation.buffer.OffsetSegmentGenerator.prototype.hasNarrowConcaveAngle=function(){return this.hasNarrowConcaveAngle;};jsts.operation.buffer.OffsetSegmentGenerator.prototype.init=function(distance){this.distance=distance;this.maxCurveSegmentError=this.distance*(1-Math.cos(this.filletAngleQuantum/2.0));this.segList=new jsts.operation.buffer.OffsetSegmentString();this.segList.setPrecisionModel(this.precisionModel);this.segList.setMinimumVertexDistance(this.distance*jsts.operation.buffer.OffsetSegmentGenerator.CURVE_VERTEX_SNAP_DISTANCE_FACTOR);};jsts.operation.buffer.OffsetSegmentGenerator.prototype.initSideSegments=function(s1,s2,side){this.s1=s1;this.s2=s2;this.side=side;this.seg1.setCoordinates(this.s1,this.s2);this.computeOffsetSegment(this.seg1,this.side,this.distance,this.offset1);};jsts.operation.buffer.OffsetSegmentGenerator.prototype.getCoordinates=function(){return this.segList.getCoordinates();};jsts.operation.buffer.OffsetSegmentGenerator.prototype.closeRing=function(){this.segList.closeRing();};jsts.operation.buffer.OffsetSegmentGenerator.prototype.addSegments=function(pt,isForward){this.segList.addPts(pt,isForward);};jsts.operation.buffer.OffsetSegmentGenerator.prototype.addFirstSegment=function(){this.segList.addPt(this.offset1.p0);};jsts.operation.buffer.OffsetSegmentGenerator.prototype.addLastSegment=function(){this.segList.addPt(this.offset1.p1);};jsts.operation.buffer.OffsetSegmentGenerator.prototype.addNextSegment=function(p,addStartPoint){this.s0=this.s1;this.s1=this.s2;this.s2=p;this.seg0.setCoordinates(this.s0,this.s1);this.computeOffsetSegment(this.seg0,this.side,this.distance,this.offset0);this.seg1.setCoordinates(this.s1,this.s2);this.computeOffsetSegment(this.seg1,this.side,this.distance,this.offset1);if(this.s1.equals(this.s2)) -return;var orientation=jsts.algorithm.CGAlgorithms.computeOrientation(this.s0,this.s1,this.s2);var outsideTurn=(orientation===jsts.algorithm.CGAlgorithms.CLOCKWISE&&this.side===jsts.geomgraph.Position.LEFT)||(orientation===jsts.algorithm.CGAlgorithms.COUNTERCLOCKWISE&&this.side===jsts.geomgraph.Position.RIGHT);if(orientation==0){this.addCollinear(addStartPoint);}else if(outsideTurn){this.addOutsideTurn(orientation,addStartPoint);}else{this.addInsideTurn(orientation,addStartPoint);}};jsts.operation.buffer.OffsetSegmentGenerator.prototype.addCollinear=function(addStartPoint){this.li.computeIntersection(this.s0,this.s1,this.s1,this.s2);var numInt=this.li.getIntersectionNum();if(numInt>=2){if(this.bufParams.getJoinStyle()===jsts.operation.buffer.BufferParameters.JOIN_BEVEL||this.bufParams.getJoinStyle()===jsts.operation.buffer.BufferParameters.JOIN_MITRE){if(addStartPoint) -this.segList.addPt(this.offset0.p1);this.segList.addPt(this.offset1.p0);}else{this.addFillet(this.s1,this.offset0.p1,this.offset1.p0,jsts.algorithm.CGAlgorithms.CLOCKWISE,this.distance);}}};jsts.operation.buffer.OffsetSegmentGenerator.prototype.addOutsideTurn=function(orientation,addStartPoint){if(this.offset0.p1.distance(this.offset1.p0)0){var mid0=new jsts.geom.Coordinate((this.closingSegLengthFactor*this.offset0.p1.x+this.s1.x)/(this.closingSegLengthFactor+1),(this.closingSegLengthFactor*this.offset0.p1.y+this.s1.y)/(this.closingSegLengthFactor+1));this.segList.addPt(mid0);var mid1=new jsts.geom.Coordinate((this.closingSegLengthFactor*this.offset1.p0.x+this.s1.x)/(this.closingSegLengthFactor+1),(this.closingSegLengthFactor*this.offset1.p0.y+this.s1.y)/(this.closingSegLengthFactor+1));this.segList.addPt(mid1);}else{this.segList.addPt(this.s1);} -this.segList.addPt(this.offset1.p0);}}};jsts.operation.buffer.OffsetSegmentGenerator.prototype.computeOffsetSegment=function(seg,side,distance,offset){var sideSign=side===jsts.geomgraph.Position.LEFT?1:-1;var dx=seg.p1.x-seg.p0.x;var dy=seg.p1.y-seg.p0.y;var len=Math.sqrt(dx*dx+dy*dy);var ux=sideSign*distance*dx/len;var uy=sideSign*distance*dy/len;offset.p0.x=seg.p0.x-uy;offset.p0.y=seg.p0.y+ux;offset.p1.x=seg.p1.x-uy;offset.p1.y=seg.p1.y+ux;};jsts.operation.buffer.OffsetSegmentGenerator.prototype.addLineEndCap=function(p0,p1){var seg=new jsts.geom.LineSegment(p0,p1);var offsetL=new jsts.geom.LineSegment();this.computeOffsetSegment(seg,jsts.geomgraph.Position.LEFT,this.distance,offsetL);var offsetR=new jsts.geom.LineSegment();this.computeOffsetSegment(seg,jsts.geomgraph.Position.RIGHT,this.distance,offsetR);var dx=p1.x-p0.x;var dy=p1.y-p0.y;var angle=Math.atan2(dy,dx);switch(this.bufParams.getEndCapStyle()){case jsts.operation.buffer.BufferParameters.CAP_ROUND:this.segList.addPt(offsetL.p1);this.addFillet(p1,angle+Math.PI/2,angle-Math.PI/2,jsts.algorithm.CGAlgorithms.CLOCKWISE,this.distance);this.segList.addPt(offsetR.p1);break;case jsts.operation.buffer.BufferParameters.CAP_FLAT:this.segList.addPt(offsetL.p1);this.segList.addPt(offsetR.p1);break;case jsts.operation.buffer.BufferParameters.CAP_SQUARE:var squareCapSideOffset=new jsts.geom.Coordinate();squareCapSideOffset.x=Math.abs(this.distance)*Math.cos(angle);squareCapSideOffset.y=Math.abs(this.distance)*Math.sin(angle);var squareCapLOffset=new jsts.geom.Coordinate(offsetL.p1.x+ -squareCapSideOffset.x,offsetL.p1.y+squareCapSideOffset.y);var squareCapROffset=new jsts.geom.Coordinate(offsetR.p1.x+ -squareCapSideOffset.x,offsetR.p1.y+squareCapSideOffset.y);this.segList.addPt(squareCapLOffset);this.segList.addPt(squareCapROffset);break;}};jsts.operation.buffer.OffsetSegmentGenerator.prototype.addMitreJoin=function(p,offset0,offset1,distance){var isMitreWithinLimit=true;var intPt=null;try{intPt=jsts.algorithm.HCoordinate.intersection(offset0.p0,offset0.p1,offset1.p0,offset1.p1);var mitreRatio=distance<=0.0?1.0:intPt.distance(p)/Math.abs(distance);if(mitreRatio>this.bufParams.getMitreLimit()) -this.isMitreWithinLimit=false;}catch(e){if(e instanceof jsts.error.NotRepresentableError){intPt=new jsts.geom.Coordinate(0,0);this.isMitreWithinLimit=false;}} -if(isMitreWithinLimit){this.segList.addPt(intPt);}else{this.addLimitedMitreJoin(offset0,offset1,distance,bufParams.getMitreLimit());}};jsts.operation.buffer.OffsetSegmentGenerator.prototype.addLimitedMitreJoin=function(offset0,offset1,distance,mitreLimit){var basePt=this.seg0.p1;var ang0=jsts.algorithm.Angle.angle(basePt,this.seg0.p0);var ang1=jsts.algorithm.Angle.angle(basePt,this.seg1.p1);var angDiff=jsts.algorithm.Angle.angleBetweenOriented(this.seg0.p0,basePt,this.seg1.p1);var angDiffHalf=angDiff/2;var midAng=jsts.algorithm.Angle.normalize(ang0+angDiffHalf);var mitreMidAng=jsts.algorithm.Angle.normalize(midAng+Math.PI);var mitreDist=mitreLimit*distance;var bevelDelta=mitreDist*Math.abs(Math.sin(angDiffHalf));var bevelHalfLen=distance-bevelDelta;var bevelMidX=basePt.x+mitreDist*Math.cos(mitreMidAng);var bevelMidY=basePt.y+mitreDist*Math.sin(mitreMidAng);var bevelMidPt=new jsts.geom.Coordinate(bevelMidX,bevelMidY);var mitreMidLine=new jsts.geom.LineSegment(basePt,bevelMidPt);var bevelEndLeft=mitreMidLine.pointAlongOffset(1.0,bevelHalfLen);var bevelEndRight=mitreMidLine.pointAlongOffset(1.0,-bevelHalfLen);if(this.side==jsts.geomgraph.Position.LEFT){this.segList.addPt(bevelEndLeft);this.segList.addPt(bevelEndRight);}else{this.segList.addPt(bevelEndRight);this.segList.addPt(bevelEndLeft);}};jsts.operation.buffer.OffsetSegmentGenerator.prototype.addBevelJoin=function(offset0,offset1){this.segList.addPt(offset0.p1);this.segList.addPt(offset1.p0);};jsts.operation.buffer.OffsetSegmentGenerator.prototype.addFillet=function(p,p0,p1,direction,radius){if(!(p1 instanceof jsts.geom.Coordinate)){this.addFillet2.apply(this,arguments);return;} -var dx0=p0.x-p.x;var dy0=p0.y-p.y;var startAngle=Math.atan2(dy0,dx0);var dx1=p1.x-p.x;var dy1=p1.y-p.y;var endAngle=Math.atan2(dy1,dx1);if(direction===jsts.algorithm.CGAlgorithms.CLOCKWISE){if(startAngle<=endAngle) -startAngle+=2.0*Math.PI;}else{if(startAngle>=endAngle) -startAngle-=2.0*Math.PI;} -this.segList.addPt(p0);this.addFillet(p,startAngle,endAngle,direction,radius);this.segList.addPt(p1);};jsts.operation.buffer.OffsetSegmentGenerator.prototype.addFillet2=function(p,startAngle,endAngle,direction,radius){var directionFactor=direction===jsts.algorithm.CGAlgorithms.CLOCKWISE?-1:1;var totalAngle=Math.abs(startAngle-endAngle);var nSegs=parseInt((totalAngle/this.filletAngleQuantum+0.5));if(nSegs<1) -return;var initAngle,currAngleInc;initAngle=0.0;currAngleInc=totalAngle/nSegs;var currAngle=initAngle;var pt=new jsts.geom.Coordinate();while(currAnglex2){return x1;} -return x2;};jsts.geomgraph.index.MonotoneChainEdge.prototype.computeIntersects=function(mce,si){for(var i=0;i=iPrev) -pPrev=eiPrev.coord;var label=new jsts.geomgraph.Label(edge.getLabel());label.flip();var e=new jsts.geomgraph.EdgeEnd(edge,eiCurr.coord,pPrev,label);l.add(e);};jsts.operation.relate.EdgeEndBuilder.prototype.createEdgeEndForNext=function(edge,l,eiCurr,eiNext){var iNext=eiCurr.segmentIndex+1;if(iNext>=edge.getNumPoints()&&eiNext===null) -return;var pNext=edge.getCoordinate(iNext);if(eiNext!==null&&eiNext.segmentIndex===eiCurr.segmentIndex) -pNext=eiNext.coord;var e=new jsts.geomgraph.EdgeEnd(edge,eiCurr.coord,pNext,new jsts.geomgraph.Label(edge.getLabel()));l.add(e);};})();(function(){var ArrayList=javascript.util.ArrayList;var TreeSet=javascript.util.TreeSet;var CoordinateFilter=jsts.geom.CoordinateFilter;jsts.util.UniqueCoordinateArrayFilter=function(){this.treeSet=new TreeSet();this.list=new ArrayList();};jsts.util.UniqueCoordinateArrayFilter.prototype=new CoordinateFilter();jsts.util.UniqueCoordinateArrayFilter.prototype.treeSet=null;jsts.util.UniqueCoordinateArrayFilter.prototype.list=null;jsts.util.UniqueCoordinateArrayFilter.prototype.getCoordinates=function(){return this.list.toArray();};jsts.util.UniqueCoordinateArrayFilter.prototype.filter=function(coord){if(!this.treeSet.contains(coord)){this.list.add(coord);this.treeSet.add(coord);}};})();(function(){var CGAlgorithms=jsts.algorithm.CGAlgorithms;var UniqueCoordinateArrayFilter=jsts.util.UniqueCoordinateArrayFilter;var Assert=jsts.util.Assert;var Stack=javascript.util.Stack;var ArrayList=javascript.util.ArrayList;var Arrays=javascript.util.Arrays;var RadialComparator=function(origin){this.origin=origin;};RadialComparator.prototype.origin=null;RadialComparator.prototype.compare=function(o1,o2){var p1=o1;var p2=o2;return RadialComparator.polarCompare(this.origin,p1,p2);};RadialComparator.polarCompare=function(o,p,q){var dxp=p.x-o.x;var dyp=p.y-o.y;var dxq=q.x-o.x;var dyq=q.y-o.y;var orient=CGAlgorithms.computeOrientation(o,p,q);if(orient==CGAlgorithms.COUNTERCLOCKWISE) -return 1;if(orient==CGAlgorithms.CLOCKWISE) -return-1;var op=dxp*dxp+dyp*dyp;var oq=dxq*dxq+dyq*dyq;if(opoq){return 1;} -return 0;};jsts.algorithm.ConvexHull=function(){if(arguments.length===1){var geometry=arguments[0];this.inputPts=jsts.algorithm.ConvexHull.extractCoordinates(geometry);this.geomFactory=geometry.getFactory();}else{this.pts=arguments[0];this.geomFactory=arguments[1];}};jsts.algorithm.ConvexHull.prototype.geomFactory=null;jsts.algorithm.ConvexHull.prototype.inputPts=null;jsts.algorithm.ConvexHull.extractCoordinates=function(geom){var filter=new UniqueCoordinateArrayFilter();geom.apply(filter);return filter.getCoordinates();};jsts.algorithm.ConvexHull.prototype.getConvexHull=function(){if(this.inputPts.length==0){return this.geomFactory.createGeometryCollection(null);} -if(this.inputPts.length==1){return this.geomFactory.createPoint(this.inputPts[0]);} -if(this.inputPts.length==2){return this.geomFactory.createLineString(this.inputPts);} -var reducedPts=this.inputPts;if(this.inputPts.length>50){reducedPts=this.reduce(this.inputPts);} -var sortedPts=this.preSort(reducedPts);var cHS=this.grahamScan(sortedPts);var cH=cHS.toArray();return this.lineOrPolygon(cH);};jsts.algorithm.ConvexHull.prototype.reduce=function(inputPts){var polyPts=this.computeOctRing(inputPts);if(polyPts==null) -return this.inputPts;var reducedSet=new javascript.util.TreeSet();for(var i=0;i0){p=ps.pop();} -p=ps.push(p);p=ps.push(c[i]);} -p=ps.push(c[0]);return ps;};jsts.algorithm.ConvexHull.prototype.isBetween=function(c1,c2,c3){if(CGAlgorithms.computeOrientation(c1,c2,c3)!==0){return false;} -if(c1.x!=c3.x){if(c1.x<=c2.x&&c2.x<=c3.x){return true;} -if(c3.x<=c2.x&&c2.x<=c1.x){return true;}} -if(c1.y!=c3.y){if(c1.y<=c2.y&&c2.y<=c3.y){return true;} -if(c3.y<=c2.y&&c2.y<=c1.y){return true;}} -return false;};jsts.algorithm.ConvexHull.prototype.computeOctRing=function(inputPts){var octPts=this.computeOctPts(inputPts);var coordList=new jsts.geom.CoordinateList();coordList.add(octPts,false);if(coordList.size()<3){return null;} -coordList.closeRing();return coordList.toCoordinateArray();};jsts.algorithm.ConvexHull.prototype.computeOctPts=function(inputPts){var pts=[];for(var j=0;j<8;j++){pts[j]=inputPts[0];} -for(var i=1;ipts[2].y){pts[2]=inputPts[i];} -if(inputPts[i].x+inputPts[i].y>pts[3].x+pts[3].y){pts[3]=inputPts[i];} -if(inputPts[i].x>pts[4].x){pts[4]=inputPts[i];} -if(inputPts[i].x-inputPts[i].y>pts[5].x-pts[5].y){pts[5]=inputPts[i];} -if(inputPts[i].y=pts.length){index=0;} -return index;};jsts.algorithm.MinimumDiameter.computeC=function(a,b,p){return a*p.y-b*p.x;};jsts.algorithm.MinimumDiameter.computeSegmentForLine=function(a,b,c){var p0;var p1;if(Math.abs(b)>Math.abs(a)){p0=new jsts.geom.Coordinate(0,c/b);p1=new jsts.geom.Coordinate(1,c/b-a/b);} -else{p0=new jsts.geom.Coordinate(c/a,0);p1=new jsts.geom.Coordinate(c/a-b/a,1);} -return new jsts.geom.LineSegment(p0,p1);};jsts.algorithm.MinimumDiameter.prototype.getLength=function(){this.computeMinimumDiameter();return this.minWidth;};jsts.algorithm.MinimumDiameter.prototype.getWidthCoordinate=function(){this.computeMinimumDiameter();return this.minWidthPt;};jsts.algorithm.MinimumDiameter.prototype.getSupportingSegment=function(){this.computeMinimumDiameter();var coord=[this.minBaseSeg.p0,this.minBaseSeg.p1];return jsts.algorithm.MinimumDiameter.inputGeom.getFactory().createLineString(coord);};jsts.algorithm.MinimumDiameter.prototype.getDiameter=function(){this.computeMinimumDiameter();if(this.minWidthPt===null){return jsts.algorithm.MinimumDiameter.inputGeom.getFactory().createLineString(null);} -var basePt=this.minBaseSeg.project(this.minWidthPt);return jsts.algorithm.MinimumDiameter.inputGeom.getFactory().createLineString([basePt,this.minWidthPt]);};jsts.algorithm.MinimumDiameter.prototype.computeMinimumDiameter=function(){if(this.minWidthPt!==null){return;} -if(jsts.algorithm.MinimumDiameter.isConvex) -this.computeWidthConvex(jsts.algorithm.MinimumDiameter.inputGeom);else{var convexGeom=new jsts.algorithm.ConvexHull(jsts.algorithm.MinimumDiameter.inputGeom).getConvexHull();this.computeWidthConvex(convexGeom);}};jsts.algorithm.MinimumDiameter.prototype.computeWidthConvex=function(convexGeom){if(convexGeom instanceof jsts.geom.Polygon){this.convexHullPts=convexGeom.getExteriorRing().getCoordinates();}else{this.convexHullPts=convexGeom.getCoordinates();} -if(this.convexHullPts.length===0){this.minWidth=0;this.minWidthPt=null;this.minBaseSeg=null;}else if(this.convexHullPts.length===1){this.minWidth=0;this.minWidthPt=this.convexHullPts[0];this.minBaseSeg.p0=this.convexHullPts[0];this.minBaseSeg.p1=this.convexHullPts[0];}else if(this.convexHullPts.length===2||this.convexHullPts.length===3){this.minWidth=0;this.minWidthPt=this.convexHullPts[0];this.minBaseSeg.p0=this.convexHullPts[0];this.minBaseSeg.p1=this.convexHullPts[1];}else{this.computeConvexRingMinDiameter(this.convexHullPts);}};jsts.algorithm.MinimumDiameter.prototype.computeConvexRingMinDiameter=function(pts){this.minWidth=Number.MAX_VALUE;var currMaxIndex=1;var seg=new jsts.geom.LineSegment();for(var i=0;i=maxPerpDistance){maxPerpDistance=nextPerpDistance;maxIndex=nextIndex;nextIndex=jsts.algorithm.MinimumDiameter.nextIndex(pts,maxIndex);nextPerpDistance=seg.distancePerpendicular(pts[nextIndex]);} -if(maxPerpDistancemaxPara)maxPara=paraC;if(paraCmaxPerp)maxPerp=perpC;if(perpC0.0){return jsts.triangulate.quadedge.Vertex.LEFT;} -if(sa<0.0){return jsts.triangulate.quadedge.Vertex.RIGHT;} -if((a.getX()*b.getX()<0.0)||(a.getY()*b.getY()<0.0)){return jsts.triangulate.quadedge.Vertex.BEHIND;} -if(a.magn()0);};jsts.triangulate.quadedge.Vertex.prototype.rightOf=function(e){return this.isCCW(e.dest(),e.orig());};jsts.triangulate.quadedge.Vertex.prototype.leftOf=function(e){return this.isCCW(e.orig(),e.dest());};jsts.triangulate.quadedge.Vertex.prototype.bisector=function(a,b){var dx,dy,l1,l2;dx=b.getX()-a.getX();dy=b.getY()-a.getY();l1=new jsts.algorithm.HCoordinate(a.getX()+(dx/2.0),a.getY()+ -(dy/2.0),1.0);l2=new jsts.algorithm.HCoordinate(a.getX()-dy+(dx/2.0),a.getY()+ -dx+(dy/2.0),1.0);return new jsts.algorithm.HCoordinate(l1,l2);};jsts.triangulate.quadedge.Vertex.prototype.distance=function(v1,v2){return v1.p.distance(v2.p);};jsts.triangulate.quadedge.Vertex.prototype.circumRadiusRatio=function(b,c){var x,radius,edgeLength,el;x=this.circleCenter(b,c);radius=this.distance(x,b);edgeLength=this.distance(this,b);el=this.distance(b,c);if(el=1){pt=ring.getCoordinateN(0);} -this.validErr=new jsts.operation.valid.TopologyValidationError(jsts.operation.valid.TopologyValidationError.RING_NOT_CLOSED,pt);}};jsts.operation.valid.IsValidOp.prototype.checkTooFewPoints=function(graph){if(graph.hasTooFewPoints){this.validErr=new jsts.operation.valid.TopologyValidationError(jsts.operation.valid.TopologyValidationError.TOO_FEW_POINTS,graph.getInvalidPoint());return;}};jsts.operation.valid.IsValidOp.prototype.checkConsistentArea=function(graph){var cat=new jsts.operation.valid.ConsistentAreaTester(graph);var isValidArea=cat.isNodeConsistentArea();if(!isValidArea){this.validErr=new jsts.operation.valid.TopologyValidationError(jsts.operation.valid.TopologyValidationError.SELF_INTERSECTION,cat.getInvalidPoint());return;} -if(cat.hasDuplicateRings()){this.validErr=new jsts.operation.valid.TopologyValidationError(jsts.operation.valid.TopologyValidationError.DUPLICATE_RINGS,cat.getInvalidPoint());}};jsts.operation.valid.IsValidOp.prototype.checkNoSelfIntersectingRings=function(graph){for(var i=graph.getEdgeIterator();i.hasNext();){var e=i.next();this.checkNoSelfIntersectingRing(e.getEdgeIntersectionList());if(this.validErr!=null){return;}}};jsts.operation.valid.IsValidOp.prototype.checkNoSelfIntersectingRing=function(eiList){var nodeSet=[];var isFirst=true;for(var i=eiList.iterator();i.hasNext();){var ei=i.next();if(isFirst){isFirst=false;continue;} -if(nodeSet.indexOf(ei.coord)>=0){this.validErr=new jsts.operation.valid.TopologyValidationError(jsts.operation.valid.TopologyValidationError.RING_SELF_INTERSECTION,ei.coord);return;}else{nodeSet.push(ei.coord);}}};jsts.operation.valid.IsValidOp.prototype.checkHolesInShell=function(p,graph){var shell=p.getExteriorRing();var pir=new jsts.algorithm.MCPointInRing(shell);for(var i=0;i0){if(x2>0){return-sign;} -else{return sign;}} -else{if(x2>0){return sign;} -else{return-sign;}}} -if((y1===0.0)||(x2===0.0)){if(y2>0){if(x1>0){return sign;} -else{return-sign;}} -else{if(x1>0){return-sign;} -else{return sign;}}} -if(0.0y2){sign=-sign;swap=x1;x1=x2;x2=swap;swap=y1;y1=y2;y2=swap;}} -else{if(y1<=-y2){sign=-sign;x2=-x2;y2=-y2;} -else{swap=x1;x1=-x2;x2=swap;swap=y1;y1=-y2;y2=swap;}}} -else{if(0.0=y2){x1=-x1;y1=-y1;x2=-x2;y2=-y2;} -else{sign=-sign;swap=-x1;x1=-x2;x2=swap;swap=-y1;y1=-y2;y2=swap;}}} -if(0.0x2){return sign;}} -else{return sign;}} -else{if(0.0=x2){sign=-sign;x1=-x1;x2=-x2;} -else{return-sign;}}} -while(true){count=count+1;k=Math.floor(x2/x1);x2=x2-k*x1;y2=y2-k*y1;if(y2<0.0){return-sign;} -if(y2>y1){return sign;} -if(x1>x2+x2){if(y1y2+y2){return-sign;} -else{x2=x1-x2;y2=y1-y2;sign=-sign;}} -if(y2===0.0){if(x2===0.0){return 0;} -else{return-sign;}} -if(x2===0.0){return sign;} -k=Math.floor(x1/x2);x1=x1-k*x2;y1=y1-k*y2;if(y1<0.0){return sign;} -if(y1>y2){return-sign;} -if(x2>x1+x1){if(y2y1+y1){return sign;} -else{x1=x2-x1;y1=y2-y1;sign=-sign;}} -if(y1===0.0){if(x1===0.0){return 0;} -else{return sign;}} -if(x1===0.0){return-sign;}}};jsts.algorithm.RobustDeterminant.orientationIndex=function(p1,p2,q){var dx1=p2.x-p1.x;var dy1=p2.y-p1.y;var dx2=q.x-p2.x;var dy2=q.y-p2.y;return jsts.algorithm.RobustDeterminant.signOfDet2x2(dx1,dy1,dx2,dy2);};jsts.index.quadtree.NodeBase=function(){this.subnode=new Array(4);this.subnode[0]=null;this.subnode[1]=null;this.subnode[2]=null;this.subnode[3]=null;this.items=[];};jsts.index.quadtree.NodeBase.prototype.getSubnodeIndex=function(env,centre){var subnodeIndex=-1;if(env.getMinX()>=centre.x){if(env.getMinY()>=centre.y){subnodeIndex=3;} -if(env.getMaxY()<=centre.y){subnodeIndex=1;}} -if(env.getMaxX()<=centre.x){if(env.getMinY()>=centre.y){subnodeIndex=2;} -if(env.getMaxY()<=centre.y){subnodeIndex=0;}} -return subnodeIndex;};jsts.index.quadtree.NodeBase.prototype.getItems=function(){return this.items;};jsts.index.quadtree.NodeBase.prototype.hasItems=function(){return(this.items.length>0);};jsts.index.quadtree.NodeBase.prototype.add=function(item){this.items.push(item);};jsts.index.quadtree.NodeBase.prototype.remove=function(itemEnv,item){if(!this.isSearchMatch(itemEnv)){return false;} -var found=false,i=0;for(i;i<4;i++){if(this.subnode[i]!==null){found=this.subnode[i].remove(itemEnv,item);if(found){if(this.subnode[i].isPrunable()){this.subnode[i]=null;} -break;}}} -if(found){return found;} -if(this.items.indexOf(item)!==-1){for(var i=this.items.length-1;i>=0;i--){if(this.items[i]===item){this.items.splice(i,1);}} -found=true;} -return found;};jsts.index.quadtree.NodeBase.prototype.isPrunable=function(){return!(this.hasChildren()||this.hasItems());};jsts.index.quadtree.NodeBase.prototype.hasChildren=function(){var i=0;for(i;i<4;i++){if(this.subnode[i]!==null){return true;}} -return false;};jsts.index.quadtree.NodeBase.prototype.isEmpty=function(){var isEmpty=true;if(this.items.length>0){isEmpty=false;} -var i=0;for(i;i<4;i++){if(this.subnode[i]!==null){if(!this.subnode[i].isEmpty()){isEmpty=false;}}} -return isEmpty;};jsts.index.quadtree.NodeBase.prototype.addAllItems=function(resultItems){resultItems=resultItems.concat(this.items);var i=0;for(i;i<4;i++){if(this.subnode[i]!==null){resultItems=this.subnode[i].addAllItems(resultItems);}} -return resultItems;};jsts.index.quadtree.NodeBase.prototype.addAllItemsFromOverlapping=function(searchEnv,resultItems){if(!this.isSearchMatch(searchEnv)){return;} -resultItems=resultItems.concat(this.items);var i=0;for(i;i<4;i++){if(this.subnode[i]!==null){resultItems=this.subnode[i].addAllItemsFromOverlapping(searchEnv,resultItems);}}};jsts.index.quadtree.NodeBase.prototype.visit=function(searchEnv,visitor){if(!this.isSearchMatch(searchEnv)){return;} -this.visitItems(searchEnv,visitor);var i=0;for(i;i<4;i++){if(this.subnode[i]!==null){this.subnode[i].visit(searchEnv,visitor);}}};jsts.index.quadtree.NodeBase.prototype.visitItems=function(env,visitor){var i=0,il=this.items.length;for(i;imaxSubDepth){maxSubDepth=sqd;}}} -return maxSubDepth+1;};jsts.index.quadtree.NodeBase.prototype.size=function(){var subSize=0,i=0;for(i;i<4;i++){if(this.subnode[i]!==null){subSize+=this.subnode[i].size();}} -return subSize+this.items.length;};jsts.index.quadtree.NodeBase.prototype.getNodeCount=function(){var subSize=0,i=0;for(i;i<4;i++){if(this.subnode[i]!==null){subSize+=this.subnode[i].size();}} -return subSize+1;};jsts.index.quadtree.Node=function(env,level){jsts.index.quadtree.NodeBase.prototype.constructor.apply(this,arguments);this.env=env;this.level=level;this.centre=new jsts.geom.Coordinate();this.centre.x=(env.getMinX()+env.getMaxX())/2;this.centre.y=(env.getMinY()+env.getMaxY())/2;};jsts.index.quadtree.Node.prototype=new jsts.index.quadtree.NodeBase();jsts.index.quadtree.Node.createNode=function(env){var key,node;key=new jsts.index.quadtree.Key(env);node=new jsts.index.quadtree.Node(key.getEnvelope(),key.getLevel());return node;};jsts.index.quadtree.Node.createExpanded=function(node,addEnv){var expandEnv=new jsts.geom.Envelope(addEnv),largerNode;if(node!==null){expandEnv.expandToInclude(node.env);} -largerNode=jsts.index.quadtree.Node.createNode(expandEnv);if(node!==null){largerNode.insertNode(node);} -return largerNode;};jsts.index.quadtree.Node.prototype.getEnvelope=function(){return this.env;};jsts.index.quadtree.Node.prototype.isSearchMatch=function(searchEnv){return this.env.intersects(searchEnv);};jsts.index.quadtree.Node.prototype.getNode=function(searchEnv){var subnodeIndex=this.getSubnodeIndex(searchEnv,this.centre),node;if(subnodeIndex!==-1){node=this.getSubnode(subnodeIndex);return node.getNode(searchEnv);}else{return this;}};jsts.index.quadtree.Node.prototype.find=function(searchEnv){var subnodeIndex=this.getSubnodeIndex(searchEnv,this.centre),node;if(subnodeIndex===-1){return this;} -if(this.subnode[subnodeIndex]!==null){node=this.subnode[subnodeIndex];return node.find(searchEnv);} -return this;};jsts.index.quadtree.Node.prototype.insertNode=function(node){var index=this.getSubnodeIndex(node.env,this.centre),childNode;if(node.level===this.level-1){this.subnode[index]=node;}else{childNode=this.createSubnode(index);childNode.insertNode(node);this.subnode[index]=childNode;}};jsts.index.quadtree.Node.prototype.getSubnode=function(index){if(this.subnode[index]===null){this.subnode[index]=this.createSubnode(index);} -return this.subnode[index];};jsts.index.quadtree.Node.prototype.createSubnode=function(index){var minx=0.0,maxx=0.0,miny=0.0,maxy=0.0,sqEnv,node;switch(index){case 0:minx=this.env.getMinX();maxx=this.centre.x;miny=this.env.getMinY();maxy=this.centre.y;break;case 1:minx=this.centre.x;maxx=this.env.getMaxX();miny=this.env.getMinY();maxy=this.centre.y;break;case 2:minx=this.env.getMinX();maxx=this.centre.x;miny=this.centre.y;maxy=this.env.getMaxY();break;case 3:minx=this.centre.x;maxx=this.env.getMaxX();miny=this.centre.y;maxy=this.env.getMaxY();break;} -sqEnv=new jsts.geom.Envelope(minx,maxx,miny,maxy);node=new jsts.index.quadtree.Node(sqEnv,this.level-1);return node;};(function(){jsts.triangulate.quadedge.QuadEdge=function(){this.rot=null;this.vertex=null;this.next=null;this.data=null;};var QuadEdge=jsts.triangulate.quadedge.QuadEdge;jsts.triangulate.quadedge.QuadEdge.makeEdge=function(o,d){var q0,q1,q2,q3,base;q0=new QuadEdge();q1=new QuadEdge();q2=new QuadEdge();q3=new QuadEdge();q0.rot=q1;q1.rot=q2;q2.rot=q3;q3.rot=q0;q0.setNext(q0);q1.setNext(q3);q2.setNext(q2);q3.setNext(q1);base=q0;base.setOrig(o);base.setDest(d);return base;};jsts.triangulate.quadedge.QuadEdge.connect=function(a,b){var e=QuadEdge.makeEdge(a.dest(),b.orig());QuadEdge.splice(e,a.lNext());QuadEdge.splice(e.sym(),b);return e;};jsts.triangulate.quadedge.QuadEdge.splice=function(a,b){var alpha,beta,t1,t2,t3,t4;alpha=a.oNext().rot;beta=b.oNext().rot;t1=b.oNext();t2=a.oNext();t3=beta.oNext();t4=alpha.oNext();a.setNext(t1);b.setNext(t2);alpha.setNext(t3);beta.setNext(t4);};jsts.triangulate.quadedge.QuadEdge.swap=function(e){var a,b;a=e.oPrev();b=e.sym().oPrev();QuadEdge.splice(e,a);QuadEdge.splice(e.sym(),b);QuadEdge.splice(e,a.lNext());QuadEdge.splice(e.sym(),b.lNext());e.setOrig(a.dest());e.setDest(b.dest());};jsts.triangulate.quadedge.QuadEdge.prototype.getPrimary=function(){if(this.orig().getCoordinate().compareTo(this.dest().getCoordinate())<=0){return this;} -else{return this.sym();}};jsts.triangulate.quadedge.QuadEdge.prototype.setData=function(data){this.data=data;};jsts.triangulate.quadedge.QuadEdge.prototype.getData=function(){return this.data;};jsts.triangulate.quadedge.QuadEdge.prototype.delete_jsts=function(){this.rot=null;};jsts.triangulate.quadedge.QuadEdge.prototype.isLive=function(){return this.rot!==null;};jsts.triangulate.quadedge.QuadEdge.prototype.setNext=function(next){this.next=next;};jsts.triangulate.quadedge.QuadEdge.prototype.invRot=function(){return this.rot.sym();};jsts.triangulate.quadedge.QuadEdge.prototype.sym=function(){return this.rot.rot;};jsts.triangulate.quadedge.QuadEdge.prototype.oNext=function(){return this.next;};jsts.triangulate.quadedge.QuadEdge.prototype.oPrev=function(){return this.rot.next.rot;};jsts.triangulate.quadedge.QuadEdge.prototype.dNext=function(){return this.sym().oNext().sym();};jsts.triangulate.quadedge.QuadEdge.prototype.dPrev=function(){return this.invRot().oNext().invRot();};jsts.triangulate.quadedge.QuadEdge.prototype.lNext=function(){return this.invRot().oNext().rot;};jsts.triangulate.quadedge.QuadEdge.prototype.lPrev=function(){return this.next.sym();};jsts.triangulate.quadedge.QuadEdge.prototype.rNext=function(){return this.rot.next.invRot();};jsts.triangulate.quadedge.QuadEdge.prototype.rPrev=function(){return this.sym().oNext();};jsts.triangulate.quadedge.QuadEdge.prototype.setOrig=function(o){this.vertex=o;};jsts.triangulate.quadedge.QuadEdge.prototype.setDest=function(d){this.sym().setOrig(d);};jsts.triangulate.quadedge.QuadEdge.prototype.orig=function(){return this.vertex;};jsts.triangulate.quadedge.QuadEdge.prototype.dest=function(){return this.sym().orig();};jsts.triangulate.quadedge.QuadEdge.prototype.getLength=function(){return this.orig().getCoordinate().distance(dest().getCoordinate());};jsts.triangulate.quadedge.QuadEdge.prototype.equalsNonOriented=function(qe){if(this.equalsOriented(qe)){return true;} -if(this.equalsOriented(qe.sym())){return true;} -return false;};jsts.triangulate.quadedge.QuadEdge.prototype.equalsOriented=function(qe){if(this.orig().getCoordinate().equals2D(qe.orig().getCoordinate())&&this.dest().getCoordinate().equals2D(qe.dest().getCoordinate())){return true;} -return false;};jsts.triangulate.quadedge.QuadEdge.prototype.toLineSegment=function() -{return new jsts.geom.LineSegment(this.vertex.getCoordinate(),this.dest().getCoordinate());};jsts.triangulate.quadedge.QuadEdge.prototype.toString=function(){var p0,p1;p0=this.vertex.getCoordinate();p1=this.dest().getCoordinate();return jsts.io.WKTWriter.toLineString(p0,p1);};})();(function(){var Assert=jsts.util.Assert;jsts.geomgraph.EdgeEnd=function(edge,p0,p1,label){this.edge=edge;if(p0&&p1){this.init(p0,p1);} -if(label){this.label=label||null;}};jsts.geomgraph.EdgeEnd.prototype.edge=null;jsts.geomgraph.EdgeEnd.prototype.label=null;jsts.geomgraph.EdgeEnd.prototype.node=null;jsts.geomgraph.EdgeEnd.prototype.p0=null;jsts.geomgraph.EdgeEnd.prototype.p1=null;jsts.geomgraph.EdgeEnd.prototype.dx=null;jsts.geomgraph.EdgeEnd.prototype.dy=null;jsts.geomgraph.EdgeEnd.prototype.quadrant=null;jsts.geomgraph.EdgeEnd.prototype.init=function(p0,p1){this.p0=p0;this.p1=p1;this.dx=p1.x-p0.x;this.dy=p1.y-p0.y;this.quadrant=jsts.geomgraph.Quadrant.quadrant(this.dx,this.dy);Assert.isTrue(!(this.dx===0&&this.dy===0),'EdgeEnd with identical endpoints found');};jsts.geomgraph.EdgeEnd.prototype.getEdge=function(){return this.edge;};jsts.geomgraph.EdgeEnd.prototype.getLabel=function(){return this.label;};jsts.geomgraph.EdgeEnd.prototype.getCoordinate=function(){return this.p0;};jsts.geomgraph.EdgeEnd.prototype.getDirectedCoordinate=function(){return this.p1;};jsts.geomgraph.EdgeEnd.prototype.getQuadrant=function(){return this.quadrant;};jsts.geomgraph.EdgeEnd.prototype.getDx=function(){return this.dx;};jsts.geomgraph.EdgeEnd.prototype.getDy=function(){return this.dy;};jsts.geomgraph.EdgeEnd.prototype.setNode=function(node){this.node=node;};jsts.geomgraph.EdgeEnd.prototype.getNode=function(){return this.node;};jsts.geomgraph.EdgeEnd.prototype.compareTo=function(e){return this.compareDirection(e);};jsts.geomgraph.EdgeEnd.prototype.compareDirection=function(e){if(this.dx===e.dx&&this.dy===e.dy) -return 0;if(this.quadrant>e.quadrant) -return 1;if(this.quadrant0&&this.minIndexthis.minCoord.y&&pNext.y>this.minCoord.y&&orientation===jsts.algorithm.CGAlgorithms.CLOCKWISE){usePrev=true;} -if(usePrev){this.minIndex=this.minIndex-1;}};jsts.operation.buffer.RightmostEdgeFinder.prototype.checkForRightmostCoordinate=function(de){var coord=de.getEdge().getCoordinates();for(var i=0;ithis.minCoord.x){this.minDe=de;this.minIndex=i;this.minCoord=coord[i];}}};jsts.operation.buffer.RightmostEdgeFinder.prototype.getRightmostSide=function(de,index){var side=this.getRightmostSideOfSegment(de,index);if(side<0) -side=this.getRightmostSideOfSegment(de,index-1);if(side<0){this.minCoord=null;this.checkForRightmostCoordinate(de);} -return side;};jsts.operation.buffer.RightmostEdgeFinder.prototype.getRightmostSideOfSegment=function(de,i){var e=de.getEdge();var coord=e.getCoordinates();if(i<0||i+1>=coord.length) -return-1;if(coord[i].y==coord[i+1].y) -return-1;var pos=jsts.geomgraph.Position.LEFT;if(coord[i].y0.0;};jsts.triangulate.IncrementalDelaunayTriangulator.prototype.insertSites=function(vertices){var i=0,il=vertices.length,v;for(i;i0.0){cent.x=this.cg3.x/3/this.areasum2;cent.y=this.cg3.y/3/this.areasum2;}else{cent.x=this.centSum.x/this.totalLength;cent.y=this.centSum.y/this.totalLength;} -return cent;};jsts.algorithm.CentroidArea.prototype.setBasePoint=function(basePt){if(this.basePt==null) -this.basePt=basePt;};jsts.algorithm.CentroidArea.prototype.add3=function(poly){this.addShell(poly.getExteriorRing().getCoordinates());for(var i=0;ix2){return x1;} -return x2;};jsts.geomgraph.index.SweepLineSegment.prototype.computeIntersections=function(ss,si){si.addIntersections(this.edge,this.ptIndex,ss.edge,ss.ptIndex);};jsts.index.quadtree.Root=function(){jsts.index.quadtree.NodeBase.prototype.constructor.apply(this,arguments);this.origin=new jsts.geom.Coordinate(0.0,0.0);};jsts.index.quadtree.Root.prototype=new jsts.index.quadtree.NodeBase();jsts.index.quadtree.Root.prototype.insert=function(itemEnv,item){var index=this.getSubnodeIndex(itemEnv,this.origin);if(index===-1){this.add(item);return;} -var node=this.subnode[index];if(node===null||!node.getEnvelope().contains(itemEnv)){var largerNode=jsts.index.quadtree.Node.createExpanded(node,itemEnv);this.subnode[index]=largerNode;} -this.insertContained(this.subnode[index],itemEnv,item);};jsts.index.quadtree.Root.prototype.insertContained=function(tree,itemEnv,item){var isZeroX,isZeroY,node;isZeroX=jsts.index.IntervalSize.isZeroWidth(itemEnv.getMinX(),itemEnv.getMaxX());isZeroY=jsts.index.IntervalSize.isZeroWidth(itemEnv.getMinY(),itemEnv.getMaxY());if(isZeroX||isZeroY){node=tree.find(itemEnv);}else{node=tree.getNode(itemEnv);} -node.add(item);};jsts.index.quadtree.Root.prototype.isSearchMatch=function(searchEnv){return true;};jsts.geomgraph.index.MonotoneChainIndexer=function(){};jsts.geomgraph.index.MonotoneChainIndexer.toIntArray=function(list){var array=[];for(var i=list.iterator();i.hasNext();){var element=i.next();array.push(element);} -return array;};jsts.geomgraph.index.MonotoneChainIndexer.prototype.getChainStartIndices=function(pts){var start=0;var startIndexList=new javascript.util.ArrayList();startIndexList.add(start);do{var last=this.findChainEnd(pts,start);startIndexList.add(last);start=last;}while(start=list.length){return null;} -return list[index];};jsts.operation.union.CascadedPolygonUnion.prototype.reduceToGeometries=function(geomTree){var geoms=[];for(var i=0,l=geomTree.length;i=0;i--){segGen.addNextSegment(simp2[i],true);} -segGen.addLastSegment();segGen.addLineEndCap(simp2[1],simp2[0]);segGen.closeRing();};jsts.operation.buffer.OffsetCurveBuilder.prototype.computeSingleSidedBufferCurve=function(inputPts,isRightSide,segGen){var distTol=jsts.operation.buffer.OffsetCurveBuilder.simplifyTolerance(this.distance);if(isRightSide){segGen.addSegments(inputPts,true);var simp2=jsts.operation.buffer.BufferInputLineSimplifier.simplify(inputPts,-distTol);var n2=simp2.length-1;segGen.initSideSegments(simp2[n2],simp2[n2-1],jsts.geomgraph.Position.LEFT);segGen.addFirstSegment();for(var i=n2-2;i>=0;i--){segGen.addNextSegment(simp2[i],true);}}else{segGen.addSegments(inputPts,false);var simp1=jsts.operation.buffer.BufferInputLineSimplifier.simplify(inputPts,distTol);var n1=simp1.length-1;segGen.initSideSegments(simp1[0],simp1[1],jsts.geomgraph.Position.LEFT);segGen.addFirstSegment();for(var i=2;i<=n1;i++){segGen.addNextSegment(simp1[i],true);}} -segGen.addLastSegment();segGen.closeRing();};jsts.operation.buffer.OffsetCurveBuilder.prototype.computeOffsetCurve=function(inputPts,isRightSide,segGen){var distTol=jsts.operation.buffer.OffsetCurveBuilder.simplifyTolerance(this.distance);if(isRightSide){var simp2=jsts.operation.buffer.BufferInputLineSimplifier.simplify(inputPts,-distTol);var n2=simp2.length-1;segGen.initSideSegments(simp2[n2],simp2[n2-1],jsts.geomgraph.Position.LEFT);segGen.addFirstSegment();for(var i=n2-2;i>=0;i--){segGen.addNextSegment(simp2[i],true);}}else{var simp1=jsts.operation.buffer.BufferInputLineSimplifier.simplify(inputPts,distTol);var n1=simp1.length-1;segGen.initSideSegments(simp1[0],simp1[1],jsts.geomgraph.Position.LEFT);segGen.addFirstSegment();for(var i=2;i<=n1;i++){segGen.addNextSegment(simp1[i],true);}} -segGen.addLastSegment();};jsts.operation.buffer.OffsetCurveBuilder.prototype.computeRingBufferCurve=function(inputPts,side,segGen){var distTol=jsts.operation.buffer.OffsetCurveBuilder.simplifyTolerance(this.distance);if(side===jsts.geomgraph.Position.RIGHT) -distTol=-distTol;var simp=jsts.operation.buffer.BufferInputLineSimplifier.simplify(inputPts,distTol);var n=simp.length-1;segGen.initSideSegments(simp[n-1],simp[0],side);for(var i=1;i<=n;i++){var addStartPoint=i!==1;segGen.addNextSegment(simp[i],addStartPoint);} -segGen.closeRing();};(function(){var HotPixelSnapAction=function(hotPixel,parentEdge,vertexIndex){this.hotPixel=hotPixel;this.parentEdge=parentEdge;this.vertexIndex=vertexIndex;};HotPixelSnapAction.prototype=new jsts.index.chain.MonotoneChainSelectAction();HotPixelSnapAction.constructor=HotPixelSnapAction;HotPixelSnapAction.prototype.hotPixel=null;HotPixelSnapAction.prototype.parentEdge=null;HotPixelSnapAction.prototype.vertexIndex=null;HotPixelSnapAction.prototype._isNodeAdded=false;HotPixelSnapAction.prototype.isNodeAdded=function(){return this._isNodeAdded;};HotPixelSnapAction.prototype.select=function(mc,startIndex){var ss=mc.getContext();if(this.parentEdge!==null){if(ss===this.parentEdge&&startIndex===this.vertexIndex) -return;} -this._isNodeAdded=this.hotPixel.addSnappedNode(ss,startIndex);};jsts.noding.snapround.MCIndexPointSnapper=function(index){this.index=index;};jsts.noding.snapround.MCIndexPointSnapper.prototype.index=null;jsts.noding.snapround.MCIndexPointSnapper.prototype.snap=function(hotPixel,parentEdge,vertexIndex){if(arguments.length===1){this.snap2.apply(this,arguments);return;} -var pixelEnv=hotPixel.getSafeEnvelope();var hotPixelSnapAction=new HotPixelSnapAction(hotPixel,parentEdge,vertexIndex);this.index.query(pixelEnv,{visitItem:function(testChain){testChain.select(pixelEnv,hotPixelSnapAction);}});return hotPixelSnapAction.isNodeAdded();};jsts.noding.snapround.MCIndexPointSnapper.prototype.snap2=function(hotPixel){return this.snap(hotPixel,null,-1);};})();(function(){var NodeBase=function(){this.items=new javascript.util.ArrayList();this.subnode=[null,null];};NodeBase.getSubnodeIndex=function(interval,centre){var subnodeIndex=-1;if(interval.min>=centre){subnodeIndex=1;} -if(interval.max<=centre){subnodeIndex=0;} -return subnodeIndex;};NodeBase.prototype.getItems=function(){return this.items;};NodeBase.prototype.add=function(item){this.items.add(item);};NodeBase.prototype.addAllItems=function(items){items.addAll(this.items);var i=0,il=2;for(i;imaxSubDepth){maxSubDepth=sqd;}}} -return maxSubDepth+1;};NodeBase.prototype.size=function(){var subSize=0,i=0,il=2;for(i;i=0.0){if(dy>=0.0) -return jsts.geomgraph.Quadrant.NE;else -return jsts.geomgraph.Quadrant.SE;}else{if(dy>=0.0) -return jsts.geomgraph.Quadrant.NW;else -return jsts.geomgraph.Quadrant.SW;}};jsts.geomgraph.Quadrant.quadrant2=function(p0,p1){if(p1.x===p0.x&&p1.y===p0.y) -throw new jsts.error.IllegalArgumentError('Cannot compute the quadrant for two identical points '+p0);if(p1.x>=p0.x){if(p1.y>=p0.y) -return jsts.geomgraph.Quadrant.NE;else -return jsts.geomgraph.Quadrant.SE;}else{if(p1.y>=p0.y) -return jsts.geomgraph.Quadrant.NW;else -return jsts.geomgraph.Quadrant.SW;}};jsts.geomgraph.Quadrant.isOpposite=function(quad1,quad2){if(quad1===quad2) -return false;var diff=(quad1-quad2+4)%4;if(diff===2) -return true;return false;};jsts.geomgraph.Quadrant.commonHalfPlane=function(quad1,quad2){if(quad1===quad2) -return quad1;var diff=(quad1-quad2+4)%4;if(diff===2) -return-1;var min=(quad1quad2)?quad1:quad2;if(min===0&&max===3) -return 3;return min;};jsts.geomgraph.Quadrant.isInHalfPlane=function(quad,halfPlane){if(halfPlane===jsts.geomgraph.Quadrant.SE){return quad===jsts.geomgraph.Quadrant.SE||quad===jsts.geomgraph.Quadrant.SW;} -return quad===halfPlane||quad===halfPlane+1;};jsts.geomgraph.Quadrant.isNorthern=function(quad){return quad===jsts.geomgraph.Quadrant.NE||quad===jsts.geomgraph.Quadrant.NW;};jsts.operation.valid.ConsistentAreaTester=function(geomGraph){this.geomGraph=geomGraph;this.li=new jsts.algorithm.RobustLineIntersector();this.nodeGraph=new jsts.operation.relate.RelateNodeGraph();this.invalidPoint=null;};jsts.operation.valid.ConsistentAreaTester.prototype.getInvalidPoint=function(){return this.invalidPoint;};jsts.operation.valid.ConsistentAreaTester.prototype.isNodeConsistentArea=function(){var intersector=this.geomGraph.computeSelfNodes(this.li,true);if(intersector.hasProperIntersection()){this.invalidPoint=intersector.getProperIntersectionPoint();return false;} -this.nodeGraph.build(this.geomGraph);return this.isNodeEdgeAreaLabelsConsistent();};jsts.operation.valid.ConsistentAreaTester.prototype.isNodeEdgeAreaLabelsConsistent=function(){for(var nodeIt=this.nodeGraph.getNodeIterator();nodeIt.hasNext();){var node=nodeIt.next();if(!node.getEdges().isAreaLabelsConsistent(this.geomGraph)){this.invalidPoint=node.getCoordinate().clone();return false;}} -return true;};jsts.operation.valid.ConsistentAreaTester.prototype.hasDuplicateRings=function(){for(var nodeIt=this.nodeGraph.getNodeIterator();nodeIt.hasNext();){var node=nodeIt.next();for(var i=node.getEdges().iterator();i.hasNext();){var eeb=i.next();if(eeb.getEdgeEnds().length>1){invalidPoint=eeb.getEdge().getCoordinate(0);return true;}}} -return false;};jsts.operation.relate.RelateNode=function(coord,edges){jsts.geomgraph.Node.apply(this,arguments);};jsts.operation.relate.RelateNode.prototype=new jsts.geomgraph.Node();jsts.operation.relate.RelateNode.prototype.computeIM=function(im){im.setAtLeastIfValid(this.label.getLocation(0),this.label.getLocation(1),0);};jsts.operation.relate.RelateNode.prototype.updateIMFromEdges=function(im){this.edges.updateIM(im);};(function(){var Location=jsts.geom.Location;var Position=jsts.geomgraph.Position;var EdgeEnd=jsts.geomgraph.EdgeEnd;jsts.geomgraph.DirectedEdge=function(edge,isForward){EdgeEnd.call(this,edge);this.depth=[0,-999,-999];this._isForward=isForward;if(isForward){this.init(edge.getCoordinate(0),edge.getCoordinate(1));}else{var n=edge.getNumPoints()-1;this.init(edge.getCoordinate(n),edge.getCoordinate(n-1));} -this.computeDirectedLabel();};jsts.geomgraph.DirectedEdge.prototype=new EdgeEnd();jsts.geomgraph.DirectedEdge.constructor=jsts.geomgraph.DirectedEdge;jsts.geomgraph.DirectedEdge.depthFactor=function(currLocation,nextLocation){if(currLocation===Location.EXTERIOR&&nextLocation===Location.INTERIOR) -return 1;else if(currLocation===Location.INTERIOR&&nextLocation===Location.EXTERIOR) -return-1;return 0;};jsts.geomgraph.DirectedEdge.prototype._isForward=null;jsts.geomgraph.DirectedEdge.prototype._isInResult=false;jsts.geomgraph.DirectedEdge.prototype._isVisited=false;jsts.geomgraph.DirectedEdge.prototype.sym=null;jsts.geomgraph.DirectedEdge.prototype.next=null;jsts.geomgraph.DirectedEdge.prototype.nextMin=null;jsts.geomgraph.DirectedEdge.prototype.edgeRing=null;jsts.geomgraph.DirectedEdge.prototype.minEdgeRing=null;jsts.geomgraph.DirectedEdge.prototype.depth=null;jsts.geomgraph.DirectedEdge.prototype.getEdge=function(){return this.edge;};jsts.geomgraph.DirectedEdge.prototype.setInResult=function(isInResult){this._isInResult=isInResult;};jsts.geomgraph.DirectedEdge.prototype.isInResult=function(){return this._isInResult;};jsts.geomgraph.DirectedEdge.prototype.isVisited=function(){return this._isVisited;};jsts.geomgraph.DirectedEdge.prototype.setVisited=function(isVisited){this._isVisited=isVisited;};jsts.geomgraph.DirectedEdge.prototype.setEdgeRing=function(edgeRing){this.edgeRing=edgeRing;};jsts.geomgraph.DirectedEdge.prototype.getEdgeRing=function(){return this.edgeRing;};jsts.geomgraph.DirectedEdge.prototype.setMinEdgeRing=function(minEdgeRing){this.minEdgeRing=minEdgeRing;};jsts.geomgraph.DirectedEdge.prototype.getMinEdgeRing=function(){return this.minEdgeRing;};jsts.geomgraph.DirectedEdge.prototype.getDepth=function(position){return this.depth[position];};jsts.geomgraph.DirectedEdge.prototype.setDepth=function(position,depthVal){if(this.depth[position]!==-999){if(this.depth[position]!==depthVal) -throw new jsts.error.TopologyError('assigned depths do not match',this.getCoordinate());} -this.depth[position]=depthVal;};jsts.geomgraph.DirectedEdge.prototype.getDepthDelta=function(){var depthDelta=this.edge.getDepthDelta();if(!this._isForward) -depthDelta=-depthDelta;return depthDelta;};jsts.geomgraph.DirectedEdge.prototype.setVisitedEdge=function(isVisited){this.setVisited(isVisited);this.sym.setVisited(isVisited);};jsts.geomgraph.DirectedEdge.prototype.getSym=function(){return this.sym;};jsts.geomgraph.DirectedEdge.prototype.isForward=function(){return this._isForward;};jsts.geomgraph.DirectedEdge.prototype.setSym=function(de){this.sym=de;};jsts.geomgraph.DirectedEdge.prototype.getNext=function(){return this.next;};jsts.geomgraph.DirectedEdge.prototype.setNext=function(next){this.next=next;};jsts.geomgraph.DirectedEdge.prototype.getNextMin=function(){return this.nextMin;};jsts.geomgraph.DirectedEdge.prototype.setNextMin=function(nextMin){this.nextMin=nextMin;};jsts.geomgraph.DirectedEdge.prototype.isLineEdge=function(){var isLine=this.label.isLine(0)||this.label.isLine(1);var isExteriorIfArea0=!this.label.isArea(0)||this.label.allPositionsEqual(0,Location.EXTERIOR);var isExteriorIfArea1=!this.label.isArea(1)||this.label.allPositionsEqual(1,Location.EXTERIOR);return isLine&&isExteriorIfArea0&&isExteriorIfArea1;};jsts.geomgraph.DirectedEdge.prototype.isInteriorAreaEdge=function(){var isInteriorAreaEdge=true;for(var i=0;i<2;i++){if(!(this.label.isArea(i)&&this.label.getLocation(i,Position.LEFT)===Location.INTERIOR&&this.label.getLocation(i,Position.RIGHT)===Location.INTERIOR)){isInteriorAreaEdge=false;}} -return isInteriorAreaEdge;};jsts.geomgraph.DirectedEdge.prototype.computeDirectedLabel=function(){this.label=new jsts.geomgraph.Label(this.edge.getLabel());if(!this._isForward) -this.label.flip();};jsts.geomgraph.DirectedEdge.prototype.setEdgeDepths=function(position,depth){var depthDelta=this.getEdge().getDepthDelta();if(!this._isForward) -depthDelta=-depthDelta;var directionFactor=1;if(position===Position.LEFT) -directionFactor=-1;var oppositePos=Position.opposite(position);var delta=depthDelta*directionFactor;var oppositeDepth=depth+delta;this.setDepth(position,depth);this.setDepth(oppositePos,oppositeDepth);};})();jsts.operation.distance.DistanceOp=function(g0,g1,terminateDistance){this.ptLocator=new jsts.algorithm.PointLocator();this.geom=[];this.geom[0]=g0;this.geom[1]=g1;this.terminateDistance=terminateDistance;};jsts.operation.distance.DistanceOp.prototype.geom=null;jsts.operation.distance.DistanceOp.prototype.terminateDistance=0.0;jsts.operation.distance.DistanceOp.prototype.ptLocator=null;jsts.operation.distance.DistanceOp.prototype.minDistanceLocation=null;jsts.operation.distance.DistanceOp.prototype.minDistance=Number.MAX_VALUE;jsts.operation.distance.DistanceOp.distance=function(g0,g1){var distOp=new jsts.operation.distance.DistanceOp(g0,g1,0.0);return distOp.distance();};jsts.operation.distance.DistanceOp.isWithinDistance=function(g0,g1,distance){var distOp=new jsts.operation.distance.DistanceOp(g0,g1,distance);return distOp.distance()<=distance;};jsts.operation.distance.DistanceOp.nearestPoints=function(g0,g1){var distOp=new jsts.operation.distance.DistanceOp(g0,g1,0.0);return distOp.nearestPoints();};jsts.operation.distance.DistanceOp.prototype.distance=function(){if(this.geom[0]===null||this.geom[1]===null) -throw new jsts.error.IllegalArgumentError('null geometries are not supported');if(this.geom[0].isEmpty()||this.geom[1].isEmpty()) -return 0.0;this.computeMinDistance();return this.minDistance;};jsts.operation.distance.DistanceOp.prototype.nearestPoints=function(){this.computeMinDistance();var nearestPts=[this.minDistanceLocation[0].getCoordinate(),this.minDistanceLocation[1].getCoordinate()];return nearestPts;};jsts.operation.distance.DistanceOp.prototype.nearestLocations=function(){this.computeMinDistance();return this.minDistanceLocation;};jsts.operation.distance.DistanceOp.prototype.updateMinDistance=function(locGeom,flip){if(locGeom[0]===null) -return;if(flip){this.minDistanceLocation[0]=locGeom[1];this.minDistanceLocation[1]=locGeom[0];}else{this.minDistanceLocation[0]=locGeom[0];this.minDistanceLocation[1]=locGeom[1];}};jsts.operation.distance.DistanceOp.prototype.computeMinDistance=function(){if(arguments.length>0){this.computeMinDistance2.apply(this,arguments);return;} -if(this.minDistanceLocation!==null) -return;this.minDistanceLocation=[];this.computeContainmentDistance();if(this.minDistance<=this.terminateDistance) -return;this.computeFacetDistance();};jsts.operation.distance.DistanceOp.prototype.computeContainmentDistance=function(){if(arguments.length===2){this.computeContainmentDistance2.apply(this,arguments);return;}else if(arguments.length===3&&(!arguments[0]instanceof jsts.operation.distance.GeometryLocation)){this.computeContainmentDistance3.apply(this,arguments);return;}else if(arguments.length===3){this.computeContainmentDistance4.apply(this,arguments);return;} -var locPtPoly=[];this.computeContainmentDistance2(0,locPtPoly);if(this.minDistance<=this.terminateDistance) -return;this.computeContainmentDistance2(1,locPtPoly);};jsts.operation.distance.DistanceOp.prototype.computeContainmentDistance2=function(polyGeomIndex,locPtPoly){var locationsIndex=1-polyGeomIndex;var polys=jsts.geom.util.PolygonExtracter.getPolygons(this.geom[polyGeomIndex]);if(polys.length>0){var insideLocs=jsts.operation.distance.ConnectedElementLocationFilter.getLocations(this.geom[locationsIndex]);this.computeContainmentDistance3(insideLocs,polys,locPtPoly);if(this.minDistance<=this.terminateDistance){this.minDistanceLocation[locationsIndex]=locPtPoly[0];this.minDistanceLocation[polyGeomIndex]=locPtPoly[1];return;}}};jsts.operation.distance.DistanceOp.prototype.computeContainmentDistance3=function(locs,polys,locPtPoly){for(var i=0;ithis.minDistance){return;} -var coord0=line0.getCoordinates();var coord1=line1.getCoordinates();for(var i=0;ithis.minDistance){return;} -var coord0=line.getCoordinates();var coord=pt.getCoordinate();for(var i=0;i0){return this.isNull2.apply(this,arguments);} -for(var i=0;i<2;i++){for(var j=0;j<3;j++){if(this.depth[i][j]!==jsts.geomgraph.Depth.NULL_VALUE) -return false;}} -return true;};jsts.geomgraph.Depth.prototype.isNull2=function(geomIndex){if(arguments.length>1){return this.isNull3.apply(this,arguments);} -return this.depth[geomIndex][1]==jsts.geomgraph.Depth.NULL_VALUE;};jsts.geomgraph.Depth.prototype.isNull3=function(geomIndex,posIndex){return this.depth[geomIndex][posIndex]==jsts.geomgraph.Depth.NULL_VALUE;};jsts.geomgraph.Depth.prototype.add=function(lbl){for(var i=0;i<2;i++){for(var j=1;j<3;j++){var loc=lbl.getLocation(i,j);if(loc===Location.EXTERIOR||loc===Location.INTERIOR){if(this.isNull(i,j)){this.depth[i][j]=jsts.geomgraph.Depth.depthAtLocation(loc);}else -this.depth[i][j]+=jsts.geomgraph.Depth.depthAtLocation(loc);}}}};jsts.geomgraph.Depth.prototype.getDelta=function(geomIndex){return this.depth[geomIndex][Position.RIGHT]- -this.depth[geomIndex][Position.LEFT];};jsts.geomgraph.Depth.prototype.normalize=function(){for(var i=0;i<2;i++){if(!this.isNull(i)){var minDepth=this.depth[i][1];if(this.depth[i][2]minDepth) -newValue=1;this.depth[i][j]=newValue;}}}};jsts.geomgraph.Depth.prototype.toString=function(){return'A: '+this.depth[0][1]+','+this.depth[0][2]+' B: '+ -this.depth[1][1]+','+this.depth[1][2];};})();jsts.algorithm.BoundaryNodeRule=function(){};jsts.algorithm.BoundaryNodeRule.prototype.isInBoundary=function(boundaryCount){throw new jsts.error.AbstractMethodInvocationError();};jsts.algorithm.Mod2BoundaryNodeRule=function(){};jsts.algorithm.Mod2BoundaryNodeRule.prototype=new jsts.algorithm.BoundaryNodeRule();jsts.algorithm.Mod2BoundaryNodeRule.prototype.isInBoundary=function(boundaryCount){return boundaryCount%2===1;};jsts.algorithm.BoundaryNodeRule.MOD2_BOUNDARY_RULE=new jsts.algorithm.Mod2BoundaryNodeRule();jsts.algorithm.BoundaryNodeRule.OGC_SFS_BOUNDARY_RULE=jsts.algorithm.BoundaryNodeRule.MOD2_BOUNDARY_RULE;jsts.operation.distance.GeometryLocation=function(component,segIndex,pt){this.component=component;this.segIndex=segIndex;this.pt=pt;};jsts.operation.distance.GeometryLocation.INSIDE_AREA=-1;jsts.operation.distance.GeometryLocation.prototype.component=null;jsts.operation.distance.GeometryLocation.prototype.segIndex=null;jsts.operation.distance.GeometryLocation.prototype.pt=null;jsts.operation.distance.GeometryLocation.prototype.getGeometryComponent=function(){return this.component;};jsts.operation.distance.GeometryLocation.prototype.getSegmentIndex=function(){return this.segIndex;};jsts.operation.distance.GeometryLocation.prototype.getCoordinate=function(){return this.pt;};jsts.operation.distance.GeometryLocation.prototype.isInsideArea=function(){return this.segIndex===jsts.operation.distance.GeometryLocation.INSIDE_AREA;};jsts.geom.util.PointExtracter=function(pts){this.pts=pts;};jsts.geom.util.PointExtracter.prototype=new jsts.geom.GeometryFilter();jsts.geom.util.PointExtracter.prototype.pts=null;jsts.geom.util.PointExtracter.getPoints=function(geom,list){if(list===undefined){list=[];} -if(geom instanceof jsts.geom.Point){list.push(geom);}else if(geom instanceof jsts.geom.GeometryCollection||geom instanceof jsts.geom.MultiPoint||geom instanceof jsts.geom.MultiLineString||geom instanceof jsts.geom.MultiPolygon){geom.apply(new jsts.geom.util.PointExtracter(list));} -return list;};jsts.geom.util.PointExtracter.prototype.filter=function(geom){if(geom instanceof jsts.geom.Point) -this.pts.push(geom);};(function(){var Location=jsts.geom.Location;jsts.operation.relate.RelateNodeGraph=function(){this.nodes=new jsts.geomgraph.NodeMap(new jsts.operation.relate.RelateNodeFactory());};jsts.operation.relate.RelateNodeGraph.prototype.nodes=null;jsts.operation.relate.RelateNodeGraph.prototype.build=function(geomGraph){this.computeIntersectionNodes(geomGraph,0);this.copyNodesAndLabels(geomGraph,0);var eeBuilder=new jsts.operation.relate.EdgeEndBuilder();var eeList=eeBuilder.computeEdgeEnds(geomGraph.getEdgeIterator());this.insertEdgeEnds(eeList);};jsts.operation.relate.RelateNodeGraph.prototype.computeIntersectionNodes=function(geomGraph,argIndex){for(var edgeIt=geomGraph.getEdgeIterator();edgeIt.hasNext();){var e=edgeIt.next();var eLoc=e.getLabel().getLocation(argIndex);for(var eiIt=e.getEdgeIntersectionList().iterator();eiIt.hasNext();){var ei=eiIt.next();var n=this.nodes.addNode(ei.coord);if(eLoc===Location.BOUNDARY) -n.setLabelBoundary(argIndex);else{if(n.getLabel().isNull(argIndex)) -n.setLabel(argIndex,Location.INTERIOR);}}}};jsts.operation.relate.RelateNodeGraph.prototype.copyNodesAndLabels=function(geomGraph,argIndex){for(var nodeIt=geomGraph.getNodeIterator();nodeIt.hasNext();){var graphNode=nodeIt.next();var newNode=this.nodes.addNode(graphNode.getCoordinate());newNode.setLabel(argIndex,graphNode.getLabel().getLocation(argIndex));}};jsts.operation.relate.RelateNodeGraph.prototype.insertEdgeEnds=function(ee){for(var i=ee.iterator();i.hasNext();){var e=i.next();this.nodes.add(e);}};jsts.operation.relate.RelateNodeGraph.prototype.getNodeIterator=function(){return this.nodes.iterator();};})();jsts.geomgraph.index.SimpleSweepLineIntersector=function(){};jsts.geomgraph.index.SimpleSweepLineIntersector.prototype=new jsts.geomgraph.index.EdgeSetIntersector();jsts.geomgraph.index.SimpleSweepLineIntersector.prototype.events=[];jsts.geomgraph.index.SimpleSweepLineIntersector.prototype.nOverlaps=null;jsts.geomgraph.index.SimpleSweepLineIntersector.prototype.computeIntersections=function(edges,si,testAllSegments){if(si instanceof javascript.util.List){this.computeIntersections2.apply(this,arguments);return;} -if(testAllSegments){this.add(edges,null);}else{this.add(edges);} -this.computeIntersections3(si);};jsts.geomgraph.index.SimpleSweepLineIntersector.prototype.computeIntersections2=function(edges0,edges1,si){this.add(edges0,edges0);this.add(edges1,edges1);this.computeIntersections3(si);};jsts.geomgraph.index.SimpleSweepLineIntersector.prototype.add=function(edge,edgeSet){if(edge instanceof javascript.util.List){this.add2.apply(this,arguments);return;} -var pts=edge.getCoordinates();for(var i=0;iother.segmentIndex)return 1;if(this.coord.equals2D(other.coord))return 0;return jsts.noding.SegmentPointComparator.compare(this.segmentOctant,this.coord,other.coord);};(function(){jsts.io.GeoJSONWriter=function(){this.parser=new jsts.io.GeoJSONParser(this.geometryFactory);};jsts.io.GeoJSONWriter.prototype.write=function(geometry){var geoJson=this.parser.write(geometry);return geoJson;};})();jsts.io.OpenLayersParser=function(geometryFactory){this.geometryFactory=geometryFactory||new jsts.geom.GeometryFactory();};jsts.io.OpenLayersParser.prototype.read=function(geometry){if(geometry.CLASS_NAME==='OpenLayers.Geometry.Point'){return this.convertFromPoint(geometry);}else if(geometry.CLASS_NAME==='OpenLayers.Geometry.LineString'){return this.convertFromLineString(geometry);}else if(geometry.CLASS_NAME==='OpenLayers.Geometry.LinearRing'){return this.convertFromLinearRing(geometry);}else if(geometry.CLASS_NAME==='OpenLayers.Geometry.Polygon'){return this.convertFromPolygon(geometry);}else if(geometry.CLASS_NAME==='OpenLayers.Geometry.MultiPoint'){return this.convertFromMultiPoint(geometry);}else if(geometry.CLASS_NAME==='OpenLayers.Geometry.MultiLineString'){return this.convertFromMultiLineString(geometry);}else if(geometry.CLASS_NAME==='OpenLayers.Geometry.MultiPolygon'){return this.convertFromMultiPolygon(geometry);}else if(geometry.CLASS_NAME==='OpenLayers.Geometry.Collection'){return this.convertFromCollection(geometry);}};jsts.io.OpenLayersParser.prototype.convertFromPoint=function(point){return this.geometryFactory.createPoint(new jsts.geom.Coordinate(point.x,point.y));};jsts.io.OpenLayersParser.prototype.convertFromLineString=function(lineString){var i;var coordinates=[];for(i=0;i0.0){this.minExtent=delX;} -var delY=itemEnv.getHeight();if(delY0.0){this.minExtent=delY;}};jsts.operation.relate.RelateNodeFactory=function(){};jsts.operation.relate.RelateNodeFactory.prototype=new jsts.geomgraph.NodeFactory();jsts.operation.relate.RelateNodeFactory.prototype.createNode=function(coord){return new jsts.operation.relate.RelateNode(coord,new jsts.operation.relate.EdgeEndBundleStar());};jsts.index.quadtree.Key=function(itemEnv){this.pt=new jsts.geom.Coordinate();this.level=0;this.env=null;this.computeKey(itemEnv);};jsts.index.quadtree.Key.computeQuadLevel=function(env){var dx,dy,dMax,level;dx=env.getWidth();dy=env.getHeight();dMax=dx>dy?dx:dy;level=jsts.index.DoubleBits.exponent(dMax)+1;return level;};jsts.index.quadtree.Key.prototype.getPoint=function(){return this.pt;};jsts.index.quadtree.Key.prototype.getLevel=function(){return this.level;};jsts.index.quadtree.Key.prototype.getEnvelope=function(){return this.env;};jsts.index.quadtree.Key.prototype.getCentre=function(){var x,y;x=(this.env.getMinX()+this.env.getMaxX())/2;y=(this.env.getMinY()+this.env.getMaxY())/2;return new jsts.geom.Coordinate(x,y);};jsts.index.quadtree.Key.prototype.computeKey=function(){if(arguments[0]instanceof jsts.geom.Envelope){this.computeKeyFromEnvelope(arguments[0]);}else{this.computeKeyFromLevel(arguments[0],arguments[1]);}};jsts.index.quadtree.Key.prototype.computeKeyFromEnvelope=function(env){this.level=jsts.index.quadtree.Key.computeQuadLevel(env);this.env=new jsts.geom.Envelope();this.computeKey(this.level,env);while(!this.env.contains(env)){this.level+=1;this.computeKey(this.level,env);}};jsts.index.quadtree.Key.prototype.computeKeyFromLevel=function(level,env){var quadSize=jsts.index.DoubleBits.powerOf2(level);this.pt.x=Math.floor(env.getMinX()/quadSize)*quadSize;this.pt.y=Math.floor(env.getMinY()/quadSize)*quadSize;this.env.init(this.pt.x,this.pt.x+quadSize,this.pt.y,this.pt.y+ -quadSize);};jsts.geom.CoordinateArrays=function(){throw new jsts.error.AbstractMethodInvocationError();};jsts.geom.CoordinateArrays.copyDeep=function(){if(arguments.length===1){return jsts.geom.CoordinateArrays.copyDeep1(arguments[0]);}else if(arguments.length===5){jsts.geom.CoordinateArrays.copyDeep2(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4]);}};jsts.geom.CoordinateArrays.copyDeep1=function(coordinates){var copy=[];for(var i=0;i0){minCoord=coordinates[i];}} -return minCoord;};jsts.geom.CoordinateArrays.scroll=function(coordinates,firstCoordinate){var i=jsts.geom.CoordinateArrays.indexOf(firstCoordinate,coordinates);if(i<0) -return;var newCoordinates=coordinates.slice(i).concat(coordinates.slice(0,i));for(i=0;imaxx){minx=p2.x;maxx=p1.x;} -if(this.p.x>=minx&&this.p.x<=maxx){this.isPointOnSegment=true;} -return;} -if(((p1.y>this.p.y)&&(p2.y<=this.p.y))||((p2.y>this.p.y)&&(p1.y<=this.p.y))){var x1=p1.x-this.p.x;var y1=p1.y-this.p.y;var x2=p2.x-this.p.x;var y2=p2.y-this.p.y;var xIntSign=jsts.algorithm.RobustDeterminant.signOfDet2x2(x1,y1,x2,y2);if(xIntSign===0.0){this.isPointOnSegment=true;return;} -if(y20.0){this.crossingCount++;}}};jsts.algorithm.RayCrossingCounter.prototype.isOnSegment=function(){return jsts.geom.isPointOnSegment;};jsts.algorithm.RayCrossingCounter.prototype.getLocation=function(){if(this.isPointOnSegment) -return jsts.geom.Location.BOUNDARY;if((this.crossingCount%2)===1){return jsts.geom.Location.INTERIOR;} -return jsts.geom.Location.EXTERIOR;};jsts.algorithm.RayCrossingCounter.prototype.isPointInPolygon=function(){return this.getLocation()!==jsts.geom.Location.EXTERIOR;};jsts.operation.BoundaryOp=function(geom,bnRule){this.geom=geom;this.geomFact=geom.getFactory();this.bnRule=bnRule||jsts.algorithm.BoundaryNodeRule.MOD2_BOUNDARY_RULE;};jsts.operation.BoundaryOp.prototype.geom=null;jsts.operation.BoundaryOp.prototype.geomFact=null;jsts.operation.BoundaryOp.prototype.bnRule=null;jsts.operation.BoundaryOp.prototype.getBoundary=function(){if(this.geom instanceof jsts.geom.LineString)return this.boundaryLineString(this.geom);if(this.geom instanceof jsts.geom.MultiLineString)return this.boundaryMultiLineString(this.geom);return this.geom.getBoundary();};jsts.operation.BoundaryOp.prototype.getEmptyMultiPoint=function(){return this.geomFact.createMultiPoint(null);};jsts.operation.BoundaryOp.prototype.boundaryMultiLineString=function(mLine){if(this.geom.isEmpty()){return this.getEmptyMultiPoint();} -var bdyPts=this.computeBoundaryCoordinates(mLine);if(bdyPts.length==1){return this.geomFact.createPoint(bdyPts[0]);} -return this.geomFact.createMultiPoint(bdyPts);};jsts.operation.BoundaryOp.prototype.endpoints=null;jsts.operation.BoundaryOp.prototype.computeBoundaryCoordinates=function(mLine){var i,line,endpoint,bdyPts=[];this.endpoints=[];for(i=0;i0.0&&this.isErodedCompletely(hole,-this.distance)) -continue;this.addPolygonRing(holeCoord,offsetDistance,jsts.geomgraph.Position.opposite(offsetSide),jsts.geom.Location.INTERIOR,jsts.geom.Location.EXTERIOR);}};jsts.operation.buffer.OffsetCurveSetBuilder.prototype.addPolygonRing=function(coord,offsetDistance,side,cwLeftLoc,cwRightLoc){if(offsetDistance==0.0&&coord.length=jsts.geom.LinearRing.MINIMUM_VALID_SIZE&&jsts.algorithm.CGAlgorithms.isCCW(coord)){leftLoc=cwRightLoc;rightLoc=cwLeftLoc;side=jsts.geomgraph.Position.opposite(side);} -var curve=this.curveBuilder.getRingCurve(coord,side,offsetDistance);this.addCurve(curve,leftLoc,rightLoc);};jsts.operation.buffer.OffsetCurveSetBuilder.prototype.isErodedCompletely=function(ring,bufferDistance){var ringCoord=ring.getCoordinates();var minDiam=0.0;if(ringCoord.length<4) -return bufferDistance<0;if(ringCoord.length==4) -return this.isTriangleErodedCompletely(ringCoord,bufferDistance);var env=ring.getEnvelopeInternal();var envMinDimension=Math.min(env.getHeight(),env.getWidth());if(bufferDistance<0.0&&2*Math.abs(bufferDistance)>envMinDimension) -return true;return false;};jsts.operation.buffer.OffsetCurveSetBuilder.prototype.isTriangleErodedCompletely=function(triangleCoord,bufferDistance){var tri=new jsts.geom.Triangle(triangleCoord[0],triangleCoord[1],triangleCoord[2]);var inCentre=tri.inCentre();var distToCentre=jsts.algorithm.CGAlgorithms.distancePointLine(inCentre,tri.p0,tri.p1);return distToCentre=1&&de.getDepth(jsts.geomgraph.Position.LEFT)<=0&&!de.isInteriorAreaEdge()){de.setInResult(true);}}};jsts.operation.buffer.BufferSubgraph.prototype.compareTo=function(o){var graph=o;if(this.rightMostCoord.xgraph.rightMostCoord.x){return 1;} -return 0;};jsts.simplify.DPTransformer=function(distanceTolerance,isEnsureValidTopology){this.distanceTolerance=distanceTolerance;this.isEnsureValidTopology=isEnsureValidTopology;};jsts.simplify.DPTransformer.prototype=new jsts.geom.util.GeometryTransformer();jsts.simplify.DPTransformer.prototype.distanceTolerance=null;jsts.simplify.DPTransformer.prototype.isEnsureValidTopology=null;jsts.simplify.DPTransformer.prototype.transformCoordinates=function(coords,parent){var inputPts=coords;var newPts=null;if(inputPts.length==0){newPts=[];}else{newPts=jsts.simplify.DouglasPeuckerLineSimplifier.simplify(inputPts,this.distanceTolerance);} -return newPts;};jsts.simplify.DPTransformer.prototype.transformPolygon=function(geom,parent){if(geom.isEmpty()){return null;} -var rawGeom=jsts.geom.util.GeometryTransformer.prototype.transformPolygon.apply(this,arguments);if(parent instanceof jsts.geom.MultiPolygon){return rawGeom;} -return this.createValidArea(rawGeom);};jsts.simplify.DPTransformer.prototype.transformLinearRing=function(geom,parent){var removeDegenerateRings=parent instanceof jsts.geom.Polygon;var simpResult=jsts.geom.util.GeometryTransformer.prototype.transformLinearRing.apply(this,arguments);if(removeDegenerateRings&&!(simpResult instanceof jsts.geom.LinearRing)){return null;} -return simpResult;};jsts.simplify.DPTransformer.prototype.transformMultiPolygon=function(geom,parent){var rawGeom=jsts.geom.util.GeometryTransformer.prototype.transformMultiPolygon.apply(this,arguments);return this.createValidArea(rawGeom);};jsts.simplify.DPTransformer.prototype.createValidArea=function(rawAreaGeom){if(this.isEnsureValidTopology){return rawAreaGeom.buffer(0.0);} -return rawAreaGeom;};jsts.geom.util.GeometryExtracter=function(clz,comps){this.clz=clz;this.comps=comps;};jsts.geom.util.GeometryExtracter.prototype=new jsts.geom.GeometryFilter();jsts.geom.util.GeometryExtracter.prototype.clz=null;jsts.geom.util.GeometryExtracter.prototype.comps=null;jsts.geom.util.GeometryExtracter.extract=function(geom,clz,list){list=list||new javascript.util.ArrayList();if(geom instanceof clz){list.add(geom);} -else if(geom instanceof jsts.geom.GeometryCollection||geom instanceof jsts.geom.MultiPoint||geom instanceof jsts.geom.MultiLineString||geom instanceof jsts.geom.MultiPolygon){geom.apply(new jsts.geom.util.GeometryExtracter(clz,list));} -return list;};jsts.geom.util.GeometryExtracter.prototype.filter=function(geom){if(this.clz===null||geom instanceof this.clz){this.comps.add(geom);}};(function(){var OverlayOp=jsts.operation.overlay.OverlayOp;var SnapOverlayOp=jsts.operation.overlay.snap.SnapOverlayOp;var SnapIfNeededOverlayOp=function(g1,g2){this.geom=[];this.geom[0]=g1;this.geom[1]=g2;};SnapIfNeededOverlayOp.overlayOp=function(g0,g1,opCode){var op=new SnapIfNeededOverlayOp(g0,g1);return op.getResultGeometry(opCode);};SnapIfNeededOverlayOp.intersection=function(g0,g1){return overlayOp(g0,g1,OverlayOp.INTERSECTION);};SnapIfNeededOverlayOp.union=function(g0,g1){return overlayOp(g0,g1,OverlayOp.UNION);};SnapIfNeededOverlayOp.difference=function(g0,g1){return overlayOp(g0,g1,OverlayOp.DIFFERENCE);};SnapIfNeededOverlayOp.symDifference=function(g0,g1){return overlayOp(g0,g1,OverlayOp.SYMDIFFERENCE);};SnapIfNeededOverlayOp.prototype.geom=null;SnapIfNeededOverlayOp.prototype.getResultGeometry=function(opCode){var result=null;var isSuccess=false;var savedException=null;try{result=OverlayOp.overlayOp(this.geom[0],this.geom[1],opCode);var isValid=true;if(isValid) -isSuccess=true;}catch(ex){savedException=ex;} -if(!isSuccess){try{result=SnapOverlayOp.overlayOp(this.geom[0],this.geom[1],opCode);}catch(ex){throw savedException;}} -return result;};jsts.operation.overlay.snap.SnapIfNeededOverlayOp=SnapIfNeededOverlayOp;})();(function(){var GeometryExtracter=jsts.geom.util.GeometryExtracter;var CascadedPolygonUnion=jsts.operation.union.CascadedPolygonUnion;var PointGeometryUnion=jsts.operation.union.PointGeometryUnion;var OverlayOp=jsts.operation.overlay.OverlayOp;var SnapIfNeededOverlayOp=jsts.operation.overlay.snap.SnapIfNeededOverlayOp;var ArrayList=javascript.util.ArrayList;jsts.operation.union.UnaryUnionOp=function(geoms,geomFact){this.polygons=new ArrayList();this.lines=new ArrayList();this.points=new ArrayList();if(geomFact){this.geomFact=geomFact;} -this.extract(geoms);};jsts.operation.union.UnaryUnionOp.union=function(geoms,geomFact){var op=new jsts.operation.union.UnaryUnionOp(geoms,geomFact);return op.union();};jsts.operation.union.UnaryUnionOp.prototype.polygons=null;jsts.operation.union.UnaryUnionOp.prototype.lines=null;jsts.operation.union.UnaryUnionOp.prototype.points=null;jsts.operation.union.UnaryUnionOp.prototype.geomFact=null;jsts.operation.union.UnaryUnionOp.prototype.extract=function(geoms){if(geoms instanceof ArrayList){for(var i=geoms.iterator();i.hasNext();){var geom=i.next();this.extract(geom);}}else{if(this.geomFact===null){this.geomFact=geoms.getFactory();} -GeometryExtracter.extract(geoms,jsts.geom.Polygon,this.polygons);GeometryExtracter.extract(geoms,jsts.geom.LineString,this.lines);GeometryExtracter.extract(geoms,jsts.geom.Point,this.points);}};jsts.operation.union.UnaryUnionOp.prototype.union=function(){if(this.geomFact===null){return null;} -var unionPoints=null;if(this.points.size()>0){var ptGeom=this.geomFact.buildGeometry(this.points);unionPoints=this.unionNoOpt(ptGeom);} -var unionLines=null;if(this.lines.size()>0){var lineGeom=this.geomFact.buildGeometry(this.lines);unionLines=this.unionNoOpt(lineGeom);} -var unionPolygons=null;if(this.polygons.size()>0){unionPolygons=CascadedPolygonUnion.union(this.polygons);} -var unionLA=this.unionWithNull(unionLines,unionPolygons);var union=null;if(unionPoints===null){union=unionLA;}else if(unionLA===null){union=unionPoints;}else{union=PointGeometryUnion(unionPoints,unionLA);} -if(union===null){return this.geomFact.createGeometryCollection(null);} -return union;};jsts.operation.union.UnaryUnionOp.prototype.unionWithNull=function(g0,g1){if(g0===null&&g1===null){return null;} -if(g1===null){return g0;} -if(g0===null){return g1;} -return g0.union(g1);};jsts.operation.union.UnaryUnionOp.prototype.unionNoOpt=function(g0){var empty=this.geomFact.createPoint(null);return SnapIfNeededOverlayOp.overlayOp(g0,empty,OverlayOp.UNION);};}());jsts.index.kdtree.KdNode=function(){this.left=null;this.right=null;this.count=1;if(arguments.length===2){this.initializeFromCoordinate.apply(this,arguments[0],arguments[1]);}else if(arguments.length===3){this.initializeFromXY.apply(this,arguments[0],arguments[1],arguments[2]);}};jsts.index.kdtree.KdNode.prototype.initializeFromXY=function(x,y,data){this.p=new jsts.geom.Coordinate(x,y);this.data=data;};jsts.index.kdtree.KdNode.prototype.initializeFromCoordinate=function(p,data){this.p=p;this.data=data;};jsts.index.kdtree.KdNode.prototype.getX=function(){return this.p.x;};jsts.index.kdtree.KdNode.prototype.getY=function(){return this.p.y;};jsts.index.kdtree.KdNode.prototype.getCoordinate=function(){return this.p;};jsts.index.kdtree.KdNode.prototype.getData=function(){return this.data;};jsts.index.kdtree.KdNode.prototype.getLeft=function(){return this.left;};jsts.index.kdtree.KdNode.prototype.getRight=function(){return this.right;};jsts.index.kdtree.KdNode.prototype.increment=function(){this.count+=1;};jsts.index.kdtree.KdNode.prototype.getCount=function(){return this.count;};jsts.index.kdtree.KdNode.prototype.isRepeated=function(){return count>1;};jsts.index.kdtree.KdNode.prototype.setLeft=function(left){this.left=left;};jsts.index.kdtree.KdNode.prototype.setRight=function(right){this.right=right;};jsts.algorithm.InteriorPointPoint=function(geometry){this.minDistance=Number.MAX_VALUE;this.interiorPoint=null;this.centroid=geometry.getCentroid().getCoordinate();this.add(geometry);};jsts.algorithm.InteriorPointPoint.prototype.add=function(geometry){if(geometry instanceof jsts.geom.Point){this.addPoint(geometry.getCoordinate());}else if(geometry instanceof jsts.geom.GeometryCollection){for(var i=0;i0.0){this.minExtent=del;}};jsts.index.bintree.Bintree=Bintree;})();jsts.algorithm.InteriorPointArea=function(geometry){this.factory;this.interiorPoint=null;this.maxWidth=0;this.factory=geometry.getFactory();this.add(geometry);};jsts.algorithm.InteriorPointArea.avg=function(a,b){return(a+b)/2;};jsts.algorithm.InteriorPointArea.prototype.getInteriorPoint=function(){return this.interiorPoint;};jsts.algorithm.InteriorPointArea.prototype.add=function(geometry){if(geometry instanceof jsts.geom.Polygon){this.addPolygon(geometry);}else if(geometry instanceof jsts.geom.GeometryCollection){for(var i=0;ithis.maxWidth){this.interiorPoint=intPt;this.maxWidth=width;}};jsts.algorithm.InteriorPointArea.prototype.widestGeometry=function(obj){if(obj instanceof jsts.geom.GeometryCollection){var gc=obj;if(gc.isEmpty()){return gc;} -var widestGeometry=gc.getGeometryN(0);for(var i=1;iwidestGeometry.getEnvelopeInternal().getWidth()){widestGeometry=gc.getGeometryN(i);}} -return widestGeometry;}else if(obj instanceof jsts.geom.Geometry){return obj;}};jsts.algorithm.InteriorPointArea.prototype.horizontalBisector=function(geometry){var envelope=geometry.getEnvelopeInternal();var bisectY=jsts.algorithm.SafeBisectorFinder.getBisectorY(geometry);return this.factory.createLineString([new jsts.geom.Coordinate(envelope.getMinX(),bisectY),new jsts.geom.Coordinate(envelope.getMaxX(),bisectY)]);};jsts.algorithm.InteriorPointArea.prototype.centre=function(envelope){return new jsts.geom.Coordinate(jsts.algorithm.InteriorPointArea.avg(envelope.getMinX(),envelope.getMaxX()),jsts.algorithm.InteriorPointArea.avg(envelope.getMinY(),envelope.getMaxY()));};jsts.algorithm.SafeBisectorFinder=function(poly){this.poly;this.centreY;this.hiY=Number.MAX_VALUE;this.loY=-Number.MAX_VALUE;this.poly=poly;this.hiY=poly.getEnvelopeInternal().getMaxY();this.loY=poly.getEnvelopeInternal().getMinY();this.centreY=jsts.algorithm.InteriorPointArea.avg(this.loY,this.hiY);};jsts.algorithm.SafeBisectorFinder.getBisectorY=function(poly){var finder=new jsts.algorithm.SafeBisectorFinder(poly);return finder.getBisectorY();};jsts.algorithm.SafeBisectorFinder.prototype.getBisectorY=function(){this.process(this.poly.getExteriorRing());for(var i=0;ithis.loY){this.loY=y;}}else if(y>this.centreY){if(y=rectEnv.getMinX()&&elementEnv.getMaxX()<=rectEnv.getMaxX()){this.intersects=true;return;} -if(elementEnv.getMinY()>=rectEnv.getMinY()&&elementEnv.getMaxY()<=rectEnv.getMaxY()){this.intersects=true;return;}} -EnvelopeIntersectsVisitor.prototype.isDone=function(){return this.intersects==true;} -var GeometryContainsPointVisitor=function(rectangle){this.rectSeq=rectangle.getExteriorRing().getCoordinateSequence();this.rectEnv=rectangle.getEnvelopeInternal();};GeometryContainsPointVisitor.prototype=new jsts.geom.util.ShortCircuitedGeometryVisitor();GeometryContainsPointVisitor.constructor=GeometryContainsPointVisitor;GeometryContainsPointVisitor.prototype.rectSeq=null;GeometryContainsPointVisitor.prototype.rectEnv=null;GeometryContainsPointVisitor.prototype.containsPoint=false;GeometryContainsPointVisitor.prototype.containsPoint=function(){return this.containsPoint;} -GeometryContainsPointVisitor.prototype.visit=function(geom){if(!(geom instanceof jsts.geom.Polygon)) -return;var elementEnv=geom.getEnvelopeInternal();if(!this.rectEnv.intersects(elementEnv)) -return;var rectPt=new jsts.geom.Coordinate();for(var i=0;i<4;i++){this.rectSeq.getCoordinate(i,rectPt);if(!elementEnv.contains(rectPt)) -continue;if(SimplePointInAreaLocator.containsPointInPolygon(rectPt,geom)){this.containsPoint=true;return;}}} -GeometryContainsPointVisitor.prototype.isDone=function(){return this.containsPoint==true;} -var RectangleIntersectsSegmentVisitor=function(rectangle){this.rectEnv=rectangle.getEnvelopeInternal();this.rectIntersector=new RectangleLineIntersector(rectEnv);};RectangleIntersectsSegmentVisitor.prototype=new jsts.geom.util.ShortCircuitedGeometryVisitor();RectangleIntersectsSegmentVisitor.constructor=RectangleIntersectsSegmentVisitor;RectangleIntersectsSegmentVisitor.prototype.rectEnv=null;RectangleIntersectsSegmentVisitor.prototype.rectIntersector=null;RectangleIntersectsSegmentVisitor.prototype.hasIntersection=false;RectangleIntersectsSegmentVisitor.prototype.p0=null;RectangleIntersectsSegmentVisitor.prototype.p1=null;RectangleIntersectsSegmentVisitor.prototype.intersects=function(){return this.hasIntersection;} -RectangleIntersectsSegmentVisitor.prototype.visit=function(geom){var elementEnv=geom.getEnvelopeInternal();if(!this.rectEnv.intersects(elementEnv)) -return;var lines=LinearComponentExtracter.getLines(geom);this.checkIntersectionWithLineStrings(lines);} -RectangleIntersectsSegmentVisitor.prototype.checkIntersectionWithLineStrings=function(lines){for(var i=lines.iterator();i.hasNext();){var testLine=i.next();this.checkIntersectionWithSegments(testLine);if(this.hasIntersection) -return;}} -RectangleIntersectsSegmentVisitor.prototype.checkIntersectionWithSegments=function(testLine){var seq1=testLine.getCoordinateSequence();for(var j=1;jx1) -return 1;return 0;};jsts.noding.SegmentPointComparator.compareValue=function(compareSign0,compareSign1){if(compareSign0<0) -return-1;if(compareSign0>0) -return 1;if(compareSign1<0) -return-1;if(compareSign1>0) -return 1;return 0;};jsts.operation.relate.RelateOp=function(){jsts.operation.GeometryGraphOperation.apply(this,arguments);this._relate=new jsts.operation.relate.RelateComputer(this.arg);};jsts.operation.relate.RelateOp.prototype=new jsts.operation.GeometryGraphOperation();jsts.operation.relate.RelateOp.relate=function(a,b,boundaryNodeRule){var relOp=new jsts.operation.relate.RelateOp(a,b,boundaryNodeRule);var im=relOp.getIntersectionMatrix();return im;};jsts.operation.relate.RelateOp.prototype._relate=null;jsts.operation.relate.RelateOp.prototype.getIntersectionMatrix=function(){return this._relate.computeIM();};jsts.index.chain.MonotoneChain=function(pts,start,end,context){this.pts=pts;this.start=start;this.end=end;this.context=context;};jsts.index.chain.MonotoneChain.prototype.pts=null;jsts.index.chain.MonotoneChain.prototype.start=null;jsts.index.chain.MonotoneChain.prototype.end=null;jsts.index.chain.MonotoneChain.prototype.env=null;jsts.index.chain.MonotoneChain.prototype.context=null;jsts.index.chain.MonotoneChain.prototype.id=null;jsts.index.chain.MonotoneChain.prototype.setId=function(id){this.id=id;};jsts.index.chain.MonotoneChain.prototype.getId=function(){return this.id;};jsts.index.chain.MonotoneChain.prototype.getContext=function(){return this.context;};jsts.index.chain.MonotoneChain.prototype.getEnvelope=function(){if(this.env==null){var p0=this.pts[this.start];var p1=this.pts[this.end];this.env=new jsts.geom.Envelope(p0,p1);} -return this.env;};jsts.index.chain.MonotoneChain.prototype.getStartIndex=function(){return this.start;};jsts.index.chain.MonotoneChain.prototype.getEndIndex=function(){return this.end;};jsts.index.chain.MonotoneChain.prototype.getLineSegment=function(index,ls){ls.p0=this.pts[index];ls.p1=this.pts[index+1];};jsts.index.chain.MonotoneChain.prototype.getCoordinates=function(){var coord=[];var index=0;for(var i=this.start;i<=this.end;i++){coord[index++]=this.pts[i];} -return coord;};jsts.index.chain.MonotoneChain.prototype.select=function(searchEnv,mcs){this.computeSelect2(searchEnv,this.start,this.end,mcs);};jsts.index.chain.MonotoneChain.prototype.computeSelect2=function(searchEnv,start0,end0,mcs){var p0=this.pts[start0];var p1=this.pts[end0];mcs.tempEnv1.init(p0,p1);if(end0-start0===1){mcs.select(this,start0);return;} -if(!searchEnv.intersects(mcs.tempEnv1)) -return;var mid=parseInt((start0+end0)/2);if(start0=0||actualDimensionValue===Dimension.TRUE)){return true;} -if(requiredDimensionSymbol==='F'&&actualDimensionValue===Dimension.FALSE){return true;} -if(requiredDimensionSymbol==='0'&&actualDimensionValue===Dimension.P){return true;} -if(requiredDimensionSymbol==='1'&&actualDimensionValue===Dimension.L){return true;} -if(requiredDimensionSymbol==='2'&&actualDimensionValue===Dimension.A){return true;} -return false;};jsts.geom.IntersectionMatrix.matches2=function(actualDimensionSymbols,requiredDimensionSymbols){var m=new jsts.geom.IntersectionMatrix(actualDimensionSymbols);return m.matches(requiredDimensionSymbols);};jsts.geom.IntersectionMatrix.prototype.set=function(row,column,dimensionValue){if(typeof row==='string'){this.set2(row);return;} -this.matrix[row][column]=dimensionValue;};jsts.geom.IntersectionMatrix.prototype.set2=function(dimensionSymbols){for(var i=0;i=0&&column>=0){this.setAtLeast(row,column,minimumDimensionValue);}};jsts.geom.IntersectionMatrix.prototype.setAtLeast2=function(minimumDimensionSymbols){var i;for(i=0;idimensionOfGeometryB){return this.isTouches(dimensionOfGeometryB,dimensionOfGeometryA);} -if((dimensionOfGeometryA==Dimension.A&&dimensionOfGeometryB==Dimension.A)||(dimensionOfGeometryA==Dimension.L&&dimensionOfGeometryB==Dimension.L)||(dimensionOfGeometryA==Dimension.L&&dimensionOfGeometryB==Dimension.A)||(dimensionOfGeometryA==Dimension.P&&dimensionOfGeometryB==Dimension.A)||(dimensionOfGeometryA==Dimension.P&&dimensionOfGeometryB==Dimension.L)){return this.matrix[Location.INTERIOR][Location.INTERIOR]===Dimension.FALSE&&(jsts.geom.IntersectionMatrix.matches(this.matrix[Location.INTERIOR][Location.BOUNDARY],'T')||jsts.geom.IntersectionMatrix.matches(this.matrix[Location.BOUNDARY][Location.INTERIOR],'T')||jsts.geom.IntersectionMatrix.matches(this.matrix[Location.BOUNDARY][Location.BOUNDARY],'T'));} -return false;};jsts.geom.IntersectionMatrix.prototype.isCrosses=function(dimensionOfGeometryA,dimensionOfGeometryB){if((dimensionOfGeometryA==Dimension.P&&dimensionOfGeometryB==Dimension.L)||(dimensionOfGeometryA==Dimension.P&&dimensionOfGeometryB==Dimension.A)||(dimensionOfGeometryA==Dimension.L&&dimensionOfGeometryB==Dimension.A)){return jsts.geom.IntersectionMatrix.matches(this.matrix[Location.INTERIOR][Location.INTERIOR],'T')&&jsts.geom.IntersectionMatrix.matches(this.matrix[Location.INTERIOR][Location.EXTERIOR],'T');} -if((dimensionOfGeometryA==Dimension.L&&dimensionOfGeometryB==Dimension.P)||(dimensionOfGeometryA==Dimension.A&&dimensionOfGeometryB==Dimension.P)||(dimensionOfGeometryA==Dimension.A&&dimensionOfGeometryB==Dimension.L)){return jsts.geom.IntersectionMatrix.matches(matrix[Location.INTERIOR][Location.INTERIOR],'T')&&jsts.geom.IntersectionMatrix.matches(this.matrix[Location.EXTERIOR][Location.INTERIOR],'T');} -if(dimensionOfGeometryA===Dimension.L&&dimensionOfGeometryB===Dimension.L){return this.matrix[Location.INTERIOR][Location.INTERIOR]===0;} -return false;};jsts.geom.IntersectionMatrix.prototype.isWithin=function(){return jsts.geom.IntersectionMatrix.matches(this.matrix[Location.INTERIOR][Location.INTERIOR],'T')&&this.matrix[Location.INTERIOR][Location.EXTERIOR]==Dimension.FALSE&&this.matrix[Location.BOUNDARY][Location.EXTERIOR]==Dimension.FALSE;};jsts.geom.IntersectionMatrix.prototype.isContains=function(){return jsts.geom.IntersectionMatrix.matches(this.matrix[Location.INTERIOR][Location.INTERIOR],'T')&&this.matrix[Location.EXTERIOR][Location.INTERIOR]==Dimension.FALSE&&this.matrix[Location.EXTERIOR][Location.BOUNDARY]==Dimension.FALSE;};jsts.geom.IntersectionMatrix.prototype.isCovers=function(){var hasPointInCommon=jsts.geom.IntersectionMatrix.matches(this.matrix[Location.INTERIOR][Location.INTERIOR],'T')||jsts.geom.IntersectionMatrix.matches(this.matrix[Location.INTERIOR][Location.BOUNDARY],'T')||jsts.geom.IntersectionMatrix.matches(this.matrix[Location.BOUNDARY][Location.INTERIOR],'T')||jsts.geom.IntersectionMatrix.matches(this.matrix[Location.BOUNDARY][Location.BOUNDARY],'T');return hasPointInCommon&&this.matrix[Location.EXTERIOR][Location.INTERIOR]==Dimension.FALSE&&this.matrix[Location.EXTERIOR][Location.BOUNDARY]==Dimension.FALSE;};jsts.geom.IntersectionMatrix.prototype.isCoveredBy=function(){var hasPointInCommon=jsts.geom.IntersectionMatrix.matches(this.matrix[Location.INTERIOR][Location.INTERIOR],'T')||jsts.geom.IntersectionMatrix.matches(this.matrix[Location.INTERIOR][Location.BOUNDARY],'T')||jsts.geom.IntersectionMatrix.matches(this.matrix[Location.BOUNDARY][Location.INTERIOR],'T')||jsts.geom.IntersectionMatrix.matches(this.matrix[Location.BOUNDARY][Location.BOUNDARY],'T');return hasPointInCommon&&this.matrix[Location.INTERIOR][Location.EXTERIOR]===Dimension.FALSE&&this.matrix[Location.BOUNDARY][Location.EXTERIOR]===Dimension.FALSE;};jsts.geom.IntersectionMatrix.prototype.isEquals=function(dimensionOfGeometryA,dimensionOfGeometryB){if(dimensionOfGeometryA!==dimensionOfGeometryB){return false;} -return jsts.geom.IntersectionMatrix.matches(this.matrix[Location.INTERIOR][Location.INTERIOR],'T')&&this.matrix[Location.EXTERIOR][Location.INTERIOR]===Dimension.FALSE&&this.matrix[Location.INTERIOR][Location.EXTERIOR]===Dimension.FALSE&&this.matrix[Location.EXTERIOR][Location.BOUNDARY]===Dimension.FALSE&&this.matrix[Location.BOUNDARY][Location.EXTERIOR]===Dimension.FALSE;};jsts.geom.IntersectionMatrix.prototype.isOverlaps=function(dimensionOfGeometryA,dimensionOfGeometryB){if((dimensionOfGeometryA==Dimension.P&&dimensionOfGeometryB===Dimension.P)||(dimensionOfGeometryA==Dimension.A&&dimensionOfGeometryB===Dimension.A)){return jsts.geom.IntersectionMatrix.matches(this.matrix[Location.INTERIOR][Location.INTERIOR],'T')&&jsts.geom.IntersectionMatrix.matches(this.matrix[Location.INTERIOR][Location.EXTERIOR],'T')&&jsts.geom.IntersectionMatrix.matches(this.matrix[Location.EXTERIOR][Location.INTERIOR],'T');} -if(dimensionOfGeometryA===Dimension.L&&dimensionOfGeometryB===Dimension.L){return this.matrix[Location.INTERIOR][Location.INTERIOR]==1&&jsts.geom.IntersectionMatrix.matches(this.matrix[Location.INTERIOR][Location.EXTERIOR],'T')&&jsts.geom.IntersectionMatrix.matches(this.matrix[Location.EXTERIOR][Location.INTERIOR],'T');} -return false;};jsts.geom.IntersectionMatrix.prototype.matches=function(requiredDimensionSymbols){if(requiredDimensionSymbols.length!=9){throw new jsts.error.IllegalArgumentException('Should be length 9: '+ -requiredDimensionSymbols);} -for(var ai=0;ai<3;ai++){for(var bi=0;bi<3;bi++){if(!jsts.geom.IntersectionMatrix.matches(this.matrix[ai][bi],requiredDimensionSymbols.charAt(3*ai+bi))){return false;}}} -return true;};jsts.geom.IntersectionMatrix.prototype.transpose=function(){var temp=matrix[1][0];this.matrix[1][0]=this.matrix[0][1];this.matrix[0][1]=temp;temp=this.matrix[2][0];this.matrix[2][0]=this.matrix[0][2];this.matrix[0][2]=temp;temp=this.matrix[2][1];this.matrix[2][1]=this.matrix[1][2];this.matrix[1][2]=temp;return this;};jsts.geom.IntersectionMatrix.prototype.toString=function(){var ai,bi,buf='';for(ai=0;ai<3;ai++){for(bi=0;bi<3;bi++){buf+=Dimension.toDimensionSymbol(this.matrix[ai][bi]);}} -return buf;};})();jsts.triangulate.quadedge.LastFoundQuadEdgeLocator=function(subdiv){this.subdiv=subdiv;this.lastEdge=null;this.init();};jsts.triangulate.quadedge.LastFoundQuadEdgeLocator.prototype.init=function(){this.lastEdge=this.findEdge();};jsts.triangulate.quadedge.LastFoundQuadEdgeLocator.prototype.findEdge=function(){var edges=this.subdiv.getEdges();return edges[0];};jsts.triangulate.quadedge.LastFoundQuadEdgeLocator.prototype.locate=function(v){if(!this.lastEdge.isLive()){this.init();} -var e=this.subdiv.locateFromEdge(v,this.lastEdge);this.lastEdge=e;return e;};jsts.noding.SegmentNodeList=function(edge){this.nodeMap=new javascript.util.TreeMap();this.edge=edge;};jsts.noding.SegmentNodeList.prototype.nodeMap=null;jsts.noding.SegmentNodeList.prototype.iterator=function(){return this.nodeMap.values().iterator();};jsts.noding.SegmentNodeList.prototype.edge=null;jsts.noding.SegmentNodeList.prototype.getEdge=function(){return this.edge;};jsts.noding.SegmentNodeList.prototype.add=function(intPt,segmentIndex){var eiNew=new jsts.noding.SegmentNode(this.edge,intPt,segmentIndex,this.edge.getSegmentOctant(segmentIndex));var ei=this.nodeMap.get(eiNew);if(ei!==null){jsts.util.Assert.isTrue(ei.coord.equals2D(intPt),'Found equal nodes with different coordinates');return ei;} -this.nodeMap.put(eiNew,eiNew);return eiNew;};jsts.noding.SegmentNodeList.prototype.addEndpoints=function(){var maxSegIndex=this.edge.size()-1;this.add(this.edge.getCoordinate(0),0);this.add(this.edge.getCoordinate(maxSegIndex),maxSegIndex);};jsts.noding.SegmentNodeList.prototype.addCollapsedNodes=function(){var collapsedVertexIndexes=[];this.findCollapsesFromInsertedNodes(collapsedVertexIndexes);this.findCollapsesFromExistingVertices(collapsedVertexIndexes);for(var i=0;ideltaY){offset=deltaX*10.0;}else{offset=deltaY*10.0;} -this.frameVertex[0]=new jsts.triangulate.quadedge.Vertex((env.getMaxX()+env.getMinX())/2.0,env.getMaxY() -+offset);this.frameVertex[1]=new jsts.triangulate.quadedge.Vertex(env.getMinX()-offset,env.getMinY()-offset);this.frameVertex[2]=new jsts.triangulate.quadedge.Vertex(env.getMaxX()+offset,env.getMinY()-offset);this.frameEnv=new jsts.geom.Envelope(this.frameVertex[0].getCoordinate(),this.frameVertex[1].getCoordinate());this.frameEnv.expandToInclude(this.frameVertex[2].getCoordinate());};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.initSubdiv=function(){var ea,eb,ec;ea=this.makeEdge(this.frameVertex[0],this.frameVertex[1]);eb=this.makeEdge(this.frameVertex[1],this.frameVertex[2]);jsts.triangulate.quadedge.QuadEdge.splice(ea.sym(),eb);ec=this.makeEdge(this.frameVertex[2],this.frameVertex[0]);jsts.triangulate.quadedge.QuadEdge.splice(eb.sym(),ec);jsts.triangulate.quadedge.QuadEdge.splice(ec.sym(),ea);return ea;};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.getTolerance=function(){return this.tolerance;};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.getEnvelope=function(){return new jsts.geom.Envelope(this.frameEnv);};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.getEdges=function(){if(arguments.length>0){return this.getEdgesByFactory(arguments[0]);}else{return this.quadEdges;}};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.setLocator=function(locator){this.locator=locator;};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.makeEdge=function(o,d){var q=jsts.triangulate.quadedge.QuadEdge.makeEdge(o,d);this.quadEdges.push(q);return q;};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.connect=function(a,b){var q=jsts.triangulate.quadedge.QuadEdge.connect(a,b);this.quadEdges.push(q);return q;};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.delete_jsts=function(e){jsts.triangulate.quadedge.QuadEdge.splice(e,e.oPrev());jsts.triangulate.quadedge.QuadEdge.splice(e.sym(),e.sym().oPrev());var eSym,eRot,eRotSym;e.eSym=e.sym();eRot=e.rot;eRotSym=e.rot.sym();var idx=this.quadEdges.indexOf(e);if(idx!==-1){this.quadEdges.splice(idx,1);} -idx=this.quadEdges.indexOf(eSym);if(idx!==-1){this.quadEdges.splice(idx,1);} -idx=this.quadEdges.indexOf(eRot);if(idx!==-1){this.quadEdges.splice(idx,1);} -idx=this.quadEdges.indexOf(eRotSym);if(idx!==-1){this.quadEdges.splice(idx,1);} -e.delete_jsts();eSym.delete_jsts();eRot.delete_jsts();eRotSym.delete_jsts();};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.locateFromEdge=function(v,startEdge){var iter=0,maxIter=this.quadEdges.length,e;e=startEdge;while(true){iter++;if(iter>maxIter){throw new jsts.error.LocateFailureError(e.toLineSegment());} -if((v.equals(e.orig()))||(v.equals(e.dest()))){break;}else if(v.rightOf(e)){e=e.sym();}else if(!v.rightOf(e.oNext())){e=e.oNext();}else if(!v.rightOf(e.dPrev())){e=e.dPrev();}else{break;}} -return e;};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.locate=function(){if(arguments.length===1){if(arguments[0]instanceof jsts.triangulate.quadedge.Vertex){return this.locateByVertex(arguments[0]);}else{return this.locateByCoordinate(arguments[0]);}}else{return this.locateByCoordinates(arguments[0],arguments[1]);}};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.locateByVertex=function(v){return this.locator.locate(v);};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.locateByCoordinate=function(p){return this.locator.locate(new jsts.triangulate.quadedge.Vertex(p));};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.locateByCoordinates=function(p0,p1){var e,base,locEdge;var e=this.locator.locate(new jsts.triangulate.quadedge.Vertex(p0));if(e===null){return null;} -base=e;if(e.dest().getCoordinate().equals2D(p0)){base=e.sym();} -locEdge=base;do{if(locEdge.dest().getCoordinate().equals2D(p1)){return locEdge;} -locEdge=locEdge.oNext();}while(locEdge!=base);return null;};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.insertSite=function(v){var e,base,startEdge;e=this.locate(v);if((v.equals(e.orig(),this.tolerance))||(v.equals(e.dest(),this.tolerance))){return e;} -base=this.makeEdge(e.orig(),v);jsts.triangulate.quadedge.QuadEdge.splice(base,e);startEdge=base;do{base=this.connect(e,base.sym());e=base.oPrev();}while(e.lNext()!=startEdge);return startEdge;};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.isFrameEdge=function(e){if(this.isFrameVertex(e.orig())||this.isFrameVertex(e.dest())){return true;} -return false;};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.isFrameBorderEdge=function(e){var leftTri,rightTri,vLeftTriOther,vRightTriOther;leftTri=new Array(3);this.getTriangleEdges(e,leftTri);rightTri=new Array(3);this.getTriangleEdges(e.sym(),rightTri);vLeftTriOther=e.lNext().dest();if(this.isFrameVertex(vLeftTriOther)){return true;} -vRightTriOther=e.sym().lNext().dest();if(this.isFrameVertex(vRightTriOther)){return true;} -return false;};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.isFrameVertex=function(v){if(v.equals(this.frameVertex[0])){return true;} -if(v.equals(this.frameVertex[1])){return true;} -if(v.equals(this.frameVertex[2])){return true;} -return false;};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.isOnEdge=function(e,p){this.seg.setCoordinates(e.orig().getCoordinate(),e.dest().getCoordinate());var dist=this.seg.distance(p);return dist0){edge=edgeStack.pop();if(visitedEdges.indexOf(edge)===-1){priQE=edge.getPrimary();if(includeFrame||!this.isFrameEdge(priQE)){edges.push(priQE);} -edgeStack.push(edge.oNext());edgeStack.push(edge.sym().oNext());visitedEdges.push(edge);visitedEdges.push(edge.sym());}} -return edges;};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.visitTriangles=function(triVisitor,includeFrame){this.visitedKey++;var edgeStack,visitedEdges,edge,triEdges;edgeStack=[];edgeStack.push(this.startingEdge);visitedEdges=[];while(edgeStack.length>0){edge=edgeStack.pop();if(visitedEdges.indexOf(edge)===-1){triEdges=this.fetchTriangleToVisit(edge,edgeStack,includeFrame,visitedEdges);if(triEdges!==null) -triVisitor.visit(triEdges);}}};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.fetchTriangleToVisit=function(edge,edgeStack,includeFrame,visitedEdges){var curr,edgeCount,isFrame,sym;curr=edge;edgeCount=0;isFrame=false;do{this.triEdges[edgeCount]=curr;if(this.isFrameEdge(curr)){isFrame=true;} -sym=curr.sym();if(visitedEdges.indexOf(sym)===-1){edgeStack.push(sym);} -visitedEdges.push(curr);edgeCount++;curr=curr.lNext();}while(curr!==edge);if(isFrame&&!includeFrame){return null;} -return this.triEdges;};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.getTriangleEdges=function(includeFrame){var visitor=new jsts.triangulate.quadedge.TriangleEdgesListVisitor();this.visitTriangles(visitor,includeFrame);return visitor.getTriangleEdges();};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.getTriangleVertices=function(includeFrame){var visitor=new TriangleVertexListVisitor();this.visitTriangles(visitor,includeFrame);return visitor.getTriangleVertices();};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.getTriangleCoordinates=function(includeFrame){var visitor=new jsts.triangulate.quadedge.TriangleCoordinatesVisitor();this.visitTriangles(visitor,includeFrame);return visitor.getTriangles();};jsts.triangulate.quadedge.QuadEdgeSubdivision.prototype.getEdgesByFactory=function(geomFact){var quadEdges,edges,i,il,qe,coords;quadEdges=this.getPrimaryEdges(false);edges=[];i=0;il=quadEdges.length;for(i;i0){this.coordList.closeRing();pts=this.coordList.toArray();if(pts.length!==4){return;} -this.triCoords.push(pts);}};jsts.triangulate.quadedge.TriangleCoordinatesVisitor.prototype.getTriangles=function(){return this.triCoords;};jsts.operation.relate.EdgeEndBundle=function(){this.edgeEnds=[];var e=arguments[0]instanceof jsts.geomgraph.EdgeEnd?arguments[0]:arguments[1];var edge=e.getEdge();var coord=e.getCoordinate();var dirCoord=e.getDirectedCoordinate();var label=new jsts.geomgraph.Label(e.getLabel());jsts.geomgraph.EdgeEnd.call(this,edge,coord,dirCoord,label);this.insert(e);};jsts.operation.relate.EdgeEndBundle.prototype=new jsts.geomgraph.EdgeEnd();jsts.operation.relate.EdgeEndBundle.prototype.edgeEnds=null;jsts.operation.relate.EdgeEndBundle.prototype.getLabel=function(){return this.label;};jsts.operation.relate.EdgeEndBundle.prototype.getEdgeEnds=function(){return this.edgeEnds;};jsts.operation.relate.EdgeEndBundle.prototype.insert=function(e){this.edgeEnds.push(e);};jsts.operation.relate.EdgeEndBundle.prototype.computeLabel=function(boundaryNodeRule){var isArea=false;for(var i=0;i0){loc=jsts.geomgraph.GeometryGraph.determineBoundary(boundaryNodeRule,boundaryCount);} -this.label.setLocation(geomIndex,loc);};jsts.operation.relate.EdgeEndBundle.prototype.computeLabelSides=function(geomIndex){this.computeLabelSide(geomIndex,jsts.geomgraph.Position.LEFT);this.computeLabelSide(geomIndex,jsts.geomgraph.Position.RIGHT);};jsts.operation.relate.EdgeEndBundle.prototype.computeLabelSide=function(geomIndex,side){for(var i=0;imaxLen){maxLen=lenBC;} -if(lenCA>maxLen){maxLen=lenCA;} -return maxLen;};jsts.geom.Triangle.angleBisector=function(a,b,c){var len0,len2,frac,dx,dy,splitPt;len0=b.distance(a);len2=b.distance(c);frac=len0/(len0+len2);dx=c.x-a.x;dy=c.y-a.y;splitPt=new jsts.geom.Coordinate(a.x+frac*dx,a.y+frac*dy);return splitPt;};jsts.geom.Triangle.area=function(a,b,c){return Math.abs(((c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y))/2.0);};jsts.geom.Triangle.signedArea=function(a,b,c){return((c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y))/2.0;};jsts.geom.Triangle.prototype.inCentre=function(){return jsts.geom.Triangle.inCentre(this.p0,this.p1,this.p2);};jsts.noding.OrientedCoordinateArray=function(pts){this.pts=pts;this._orientation=jsts.noding.OrientedCoordinateArray.orientation(pts);};jsts.noding.OrientedCoordinateArray.prototype.pts=null;jsts.noding.OrientedCoordinateArray.prototype._orientation=undefined;jsts.noding.OrientedCoordinateArray.orientation=function(pts){return jsts.geom.CoordinateArrays.increasingDirection(pts)===1;};jsts.noding.OrientedCoordinateArray.prototype.compareTo=function(o1){var oca=o1;var comp=jsts.noding.OrientedCoordinateArray.compareOriented(this.pts,this._orientation,oca.pts,oca._orientation);return comp;};jsts.noding.OrientedCoordinateArray.compareOriented=function(pts1,orientation1,pts2,orientation2){var dir1=orientation1?1:-1;var dir2=orientation2?1:-1;var limit1=orientation1?pts1.length:-1;var limit2=orientation2?pts2.length:-1;var i1=orientation1?0:pts1.length-1;var i2=orientation2?0:pts2.length-1;var comp=0;while(true){var compPt=pts1[i1].compareTo(pts2[i2]);if(compPt!==0) -return compPt;i1+=dir1;i2+=dir2;var done1=i1===limit1;var done2=i2===limit2;if(done1&&!done2) -return-1;if(!done1&&done2) -return 1;if(done1&&done2) -return 0;}};jsts.algorithm.CentralEndpointIntersector=function(p00,p01,p10,p11){this.pts=[p00,p01,p10,p11];this.compute();};jsts.algorithm.CentralEndpointIntersector.getIntersection=function(p00,p01,p10,p11){var intor=new jsts.algorithm.CentralEndpointIntersector(p00,p01,p10,p11);return intor.getIntersection();};jsts.algorithm.CentralEndpointIntersector.prototype.pts=null;jsts.algorithm.CentralEndpointIntersector.prototype.intPt=null;jsts.algorithm.CentralEndpointIntersector.prototype.compute=function(){var centroid=jsts.algorithm.CentralEndpointIntersector.average(this.pts);this.intPt=this.findNearestPoint(centroid,this.pts);};jsts.algorithm.CentralEndpointIntersector.prototype.getIntersection=function(){return this.intPt;};jsts.algorithm.CentralEndpointIntersector.average=function(pts){var avg=new jsts.geom.Coordinate();var i,n=pts.length;for(i=0;i0){avg.x/=n;avg.y/=n;} -return avg;};jsts.algorithm.CentralEndpointIntersector.prototype.findNearestPoint=function(p,pts){var minDist=Number.MAX_VALUE;var i,result=null,dist;for(i=0;i0.0?distance:0.0;var bufEnvSize=envSize+2*expandByDistance;var bufEnvLog10=(Math.log(bufEnvSize)/Math.log(10)+1.0);var minUnitLog10=bufEnvLog10-maxPrecisionDigits;var scaleFactor=Math.pow(10.0,-minUnitLog10);return scaleFactor;};jsts.operation.buffer.BufferOp.bufferOp=function(g,distance){if(arguments.length>2){return jsts.operation.buffer.BufferOp.bufferOp2.apply(this,arguments);} -var gBuf=new jsts.operation.buffer.BufferOp(g);var geomBuf=gBuf.getResultGeometry(distance);return geomBuf;};jsts.operation.buffer.BufferOp.bufferOp2=function(g,distance,params){if(arguments.length>3){return jsts.operation.buffer.BufferOp.bufferOp3.apply(this,arguments);} -var bufOp=new jsts.operation.buffer.BufferOp(g,params);var geomBuf=bufOp.getResultGeometry(distance);return geomBuf;};jsts.operation.buffer.BufferOp.bufferOp3=function(g,distance,quadrantSegments){if(arguments.length>4){return jsts.operation.buffer.BufferOp.bufferOp4.apply(this,arguments);} -var bufOp=new jsts.operation.buffer.BufferOp(g);bufOp.setQuadrantSegments(quadrantSegments);var geomBuf=bufOp.getResultGeometry(distance);return geomBuf;};jsts.operation.buffer.BufferOp.bufferOp4=function(g,distance,quadrantSegments,endCapStyle){var bufOp=new jsts.operation.buffer.BufferOp(g);bufOp.setQuadrantSegments(quadrantSegments);bufOp.setEndCapStyle(endCapStyle);var geomBuf=bufOp.getResultGeometry(distance);return geomBuf;};jsts.operation.buffer.BufferOp.prototype.argGeom=null;jsts.operation.buffer.BufferOp.prototype.distance=null;jsts.operation.buffer.BufferOp.prototype.bufParams=null;jsts.operation.buffer.BufferOp.prototype.resultGeometry=null;jsts.operation.buffer.BufferOp.prototype.setEndCapStyle=function(endCapStyle){this.bufParams.setEndCapStyle(endCapStyle);};jsts.operation.buffer.BufferOp.prototype.setQuadrantSegments=function(quadrantSegments){this.bufParams.setQuadrantSegments(quadrantSegments);};jsts.operation.buffer.BufferOp.prototype.getResultGeometry=function(dist){this.distance=dist;this.computeGeometry();return this.resultGeometry;};jsts.operation.buffer.BufferOp.prototype.computeGeometry=function(){this.bufferOriginalPrecision();if(this.resultGeometry!==null){return;} -var argPM=this.argGeom.getPrecisionModel();if(argPM.getType()===jsts.geom.PrecisionModel.FIXED){this.bufferFixedPrecision(argPM);}else{this.bufferReducedPrecision();}};jsts.operation.buffer.BufferOp.prototype.bufferReducedPrecision=function(){var precDigits;var saveException=null;for(precDigits=jsts.operation.buffer.BufferOp.MAX_PRECISION_DIGITS;precDigits>=0;precDigits--){try{this.bufferReducedPrecision2(precDigits);}catch(ex){saveException=ex;} -if(this.resultGeometry!==null){return;}} -throw saveException;};jsts.operation.buffer.BufferOp.prototype.bufferOriginalPrecision=function(){try{var bufBuilder=new jsts.operation.buffer.BufferBuilder(this.bufParams);this.resultGeometry=bufBuilder.buffer(this.argGeom,this.distance);}catch(e){}};jsts.operation.buffer.BufferOp.prototype.bufferReducedPrecision2=function(precisionDigits){var sizeBasedScaleFactor=jsts.operation.buffer.BufferOp.precisionScaleFactor(this.argGeom,this.distance,precisionDigits);var fixedPM=new jsts.geom.PrecisionModel(sizeBasedScaleFactor);this.bufferFixedPrecision(fixedPM);};jsts.operation.buffer.BufferOp.prototype.bufferFixedPrecision=function(fixedPM){var noder=new jsts.noding.ScaledNoder(new jsts.noding.snapround.MCIndexSnapRounder(new jsts.geom.PrecisionModel(1.0)),fixedPM.getScale());var bufBuilder=new jsts.operation.buffer.BufferBuilder(this.bufParams);bufBuilder.setWorkingPrecisionModel(fixedPM);bufBuilder.setNoder(noder);this.resultGeometry=bufBuilder.buffer(this.argGeom,this.distance);};(function(){var Location=jsts.geom.Location;var Position=jsts.geomgraph.Position;var Assert=jsts.util.Assert;jsts.geomgraph.GeometryGraph=function(argIndex,parentGeom,boundaryNodeRule){jsts.geomgraph.PlanarGraph.call(this);this.lineEdgeMap=new javascript.util.HashMap();this.ptLocator=new jsts.algorithm.PointLocator();this.argIndex=argIndex;this.parentGeom=parentGeom;this.boundaryNodeRule=boundaryNodeRule||jsts.algorithm.BoundaryNodeRule.OGC_SFS_BOUNDARY_RULE;if(parentGeom!==null){this.add(parentGeom);}};jsts.geomgraph.GeometryGraph.prototype=new jsts.geomgraph.PlanarGraph();jsts.geomgraph.GeometryGraph.constructor=jsts.geomgraph.GeometryGraph;jsts.geomgraph.GeometryGraph.prototype.createEdgeSetIntersector=function(){return new jsts.geomgraph.index.SimpleMCSweepLineIntersector();};jsts.geomgraph.GeometryGraph.determineBoundary=function(boundaryNodeRule,boundaryCount){return boundaryNodeRule.isInBoundary(boundaryCount)?Location.BOUNDARY:Location.INTERIOR;};jsts.geomgraph.GeometryGraph.prototype.parentGeom=null;jsts.geomgraph.GeometryGraph.prototype.lineEdgeMap=null;jsts.geomgraph.GeometryGraph.prototype.boundaryNodeRule=null;jsts.geomgraph.GeometryGraph.prototype.useBoundaryDeterminationRule=true;jsts.geomgraph.GeometryGraph.prototype.argIndex=null;jsts.geomgraph.GeometryGraph.prototype.boundaryNodes=null;jsts.geomgraph.GeometryGraph.prototype.hasTooFewPoints=false;jsts.geomgraph.GeometryGraph.prototype.invalidPoint=null;jsts.geomgraph.GeometryGraph.prototype.areaPtLocator=null;jsts.geomgraph.GeometryGraph.prototype.ptLocator=null;jsts.geomgraph.GeometryGraph.prototype.getGeometry=function(){return this.parentGeom;};jsts.geomgraph.GeometryGraph.prototype.getBoundaryNodes=function(){if(this.boundaryNodes===null) -this.boundaryNodes=this.nodes.getBoundaryNodes(this.argIndex);return this.boundaryNodes;};jsts.geomgraph.GeometryGraph.prototype.getBoundaryNodeRule=function(){return this.boundaryNodeRule;};jsts.geomgraph.GeometryGraph.prototype.findEdge=function(line){return this.lineEdgeMap.get(line);};jsts.geomgraph.GeometryGraph.prototype.computeSplitEdges=function(edgelist){for(var i=this.edges.iterator();i.hasNext();){var e=i.next();e.eiList.addSplitEdges(edgelist);}} -jsts.geomgraph.GeometryGraph.prototype.add=function(g){if(g.isEmpty()){return;} -if(g instanceof jsts.geom.MultiPolygon) -this.useBoundaryDeterminationRule=false;if(g instanceof jsts.geom.Polygon) -this.addPolygon(g);else if(g instanceof jsts.geom.LineString) -this.addLineString(g);else if(g instanceof jsts.geom.Point) -this.addPoint(g);else if(g instanceof jsts.geom.MultiPoint) -this.addCollection(g);else if(g instanceof jsts.geom.MultiLineString) -this.addCollection(g);else if(g instanceof jsts.geom.MultiPolygon) -this.addCollection(g);else if(g instanceof jsts.geom.GeometryCollection) -this.addCollection(g);else -throw new jsts.error.IllegalArgumentError('Geometry type not supported.');};jsts.geomgraph.GeometryGraph.prototype.addCollection=function(gc){for(var i=0;i=2,'found LineString with single point');this.insertBoundaryPoint(this.argIndex,coord[0]);this.insertBoundaryPoint(this.argIndex,coord[coord.length-1]);};jsts.geomgraph.GeometryGraph.prototype.addPolygonRing=function(lr,cwLeft,cwRight){if(lr.isEmpty()) -return;var coord=jsts.geom.CoordinateArrays.removeRepeatedPoints(lr.getCoordinates());if(coord.length<4){this.hasTooFewPoints=true;this.invalidPoint=coord[0];return;} -var left=cwLeft;var right=cwRight;if(jsts.algorithm.CGAlgorithms.isCCW(coord)){left=cwRight;right=cwLeft;} -var e=new jsts.geomgraph.Edge(coord,new jsts.geomgraph.Label(this.argIndex,Location.BOUNDARY,left,right));this.lineEdgeMap.put(lr,e);this.insertEdge(e);this.insertPoint(this.argIndex,coord[0],Location.BOUNDARY);};jsts.geomgraph.GeometryGraph.prototype.addPolygon=function(p){this.addPolygonRing(p.getExteriorRing(),Location.EXTERIOR,Location.INTERIOR);for(var i=0;i=0;i--){this.addPt(pt[i]);}}};jsts.operation.buffer.OffsetSegmentString.prototype.isRedundant=function(pt){if(this.ptList.length<1) -return false;var lastPt=this.ptList[this.ptList.length-1];var ptDist=pt.distance(lastPt);if(ptDist=2) -last2Pt=this.ptList[this.ptList.length-2];if(startPt.equals(lastPt)) -return;this.ptList.push(startPt);};jsts.operation.buffer.OffsetSegmentString.prototype.reverse=function(){};jsts.operation.buffer.OffsetSegmentString.prototype.getCoordinates=function(){return this.ptList;};jsts.algorithm.distance.PointPairDistance=function(){this.pt=[new jsts.geom.Coordinate(),new jsts.geom.Coordinate()];};jsts.algorithm.distance.PointPairDistance.prototype.pt=null;jsts.algorithm.distance.PointPairDistance.prototype.distance=NaN;jsts.algorithm.distance.PointPairDistance.prototype.isNull=true;jsts.algorithm.distance.PointPairDistance.prototype.initialize=function(p0,p1,distance){if(p0===undefined){this.isNull=true;return;} -this.pt[0].setCoordinate(p0);this.pt[1].setCoordinate(p1);this.distance=distance!==undefined?distance:p0.distance(p1);this.isNull=false;};jsts.algorithm.distance.PointPairDistance.prototype.getDistance=function(){return this.distance;};jsts.algorithm.distance.PointPairDistance.prototype.getCoordinates=function(){return this.pt;};jsts.algorithm.distance.PointPairDistance.prototype.getCoordinate=function(i){return this.pt[i];};jsts.algorithm.distance.PointPairDistance.prototype.setMaximum=function(ptDist){if(arguments.length===2){this.setMaximum2.apply(this,arguments);return;} -this.setMaximum(ptDist.pt[0],ptDist.pt[1]);};jsts.algorithm.distance.PointPairDistance.prototype.setMaximum2=function(p0,p1){if(this.isNull){this.initialize(p0,p1);return;} -var dist=p0.distance(p1);if(dist>this.distance) -this.initialize(p0,p1,dist);};jsts.algorithm.distance.PointPairDistance.prototype.setMinimum=function(ptDist){if(arguments.length===2){this.setMinimum2.apply(this,arguments);return;} -this.setMinimum(ptDist.pt[0],ptDist.pt[1]);};jsts.algorithm.distance.PointPairDistance.prototype.setMinimum2=function(p0,p1){if(this.isNull){this.initialize(p0,p1);return;} -var dist=p0.distance(p1);if(dist1.0||densifyFrac<=0.0) -throw new jsts.error.IllegalArgumentError('Fraction is not in range (0.0 - 1.0]');this.densifyFrac=densifyFrac;};jsts.algorithm.distance.DiscreteHausdorffDistance.prototype.distance=function(){this.compute(this.g0,this.g1);return ptDist.getDistance();};jsts.algorithm.distance.DiscreteHausdorffDistance.prototype.orientedDistance=function(){this.computeOrientedDistance(this.g0,this.g1,this.ptDist);return this.ptDist.getDistance();};jsts.algorithm.distance.DiscreteHausdorffDistance.prototype.getCoordinates=function(){return ptDist.getCoordinates();};jsts.algorithm.distance.DiscreteHausdorffDistance.prototype.compute=function(g0,g1){this.computeOrientedDistance(g0,g1,this.ptDist);this.computeOrientedDistance(g1,g0,this.ptDist);};jsts.algorithm.distance.DiscreteHausdorffDistance.prototype.computeOrientedDistance=function(discreteGeom,geom,ptDist){var distFilter=new MaxPointDistanceFilter(geom);discreteGeom.apply(distFilter);ptDist.setMaximum(distFilter.getMaxPointDistance());if(this.densifyFrac>0){var fracFilter=new MaxDensifiedByFractionDistanceFilter(geom,this.densifyFrac);discreteGeom.apply(fracFilter);ptDist.setMaximum(fracFilter.getMaxPointDistance());}};})();jsts.algorithm.MinimumBoundingCircle=function(geom){this.input=null;this.extremalPts=null;this.centre=null;this.radius=0;this.input=geom;};jsts.algorithm.MinimumBoundingCircle.prototype.getCircle=function(){this.compute();if(this.centre===null){return this.input.getFactory().createPolygon(null,null);} -var centrePoint=this.input.getFactory().createPoint(this.centre);if(this.radius===0){return centrePoint;} -return centrePoint.buffer(this.radius);};jsts.algorithm.MinimumBoundingCircle.prototype.getExtremalPoints=function(){this.compute();return this.extremalPts;};jsts.algorithm.MinimumBoundingCircle.prototype.getCentre=function(){this.compute();return this.centre;};jsts.algorithm.MinimumBoundingCircle.prototype.getRadius=function(){this.compute();return this.radius;};jsts.algorithm.MinimumBoundingCircle.prototype.computeCentre=function(){switch(this.extremalPts.length){case 0:this.centre=null;break;case 1:this.centre=this.extremalPts[0];break;case 2:this.centre=new jsts.geom.Coordinate((this.extremalPts[0].x+this.extremalPts[1].x)/2,(this.extremalPts[0].y+this.extremalPts[1].y)/2);break;case 3:this.centre=jsts.geom.Triangle.circumcentre(this.extremalPts[0],this.extremalPts[1],this.extremalPts[2]);break;}};jsts.algorithm.MinimumBoundingCircle.prototype.compute=function(){if(this.extremalPts!==null){return;} -this.computeCirclePoints();this.computeCentre();if(this.centre!==null){this.radius=this.centre.distance(this.extremalPts[0]);}};jsts.algorithm.MinimumBoundingCircle.prototype.computeCirclePoints=function(){if(this.input.isEmpty()){this.extremalPts=[];return;} -var pts;if(this.input.getNumPoints()===1){pts=this.input.getCoordinates();this.extremalPts=[new jsts.geom.Coordinate(pts[0])];return;} -var convexHull=this.input.convexHull();var hullPts=convexHull.getCoordinates();pts=hullPts;if(hullPts[0].equals2D(hullPts[hullPts.length-1])){pts=[];jsts.geom.CoordinateArrays.copyDeep(hullPts,0,pts,0,hullPts.length-1);} -if(pts.length<=2){this.extremalPts=jsts.geom.CoordinateArrays.copyDeep(pts);return;} -var P=jsts.algorithm.MinimumBoundingCircle.lowestPoint(pts);var Q=jsts.algorithm.MinimumBoundingCircle.pointWitMinAngleWithX(pts,P);for(var i=0;ia||a>=this.size())throw new k;return this.a[a]};s.prototype.get=s.prototype.get;s.prototype.g=function(){return 0===this.a.length};s.prototype.isEmpty=s.prototype.g;s.prototype.size=function(){return this.a.length};s.prototype.size=s.prototype.size;s.prototype.h=function(){for(var a=[],b=0,c=this.a.length;bc)b=b.left;else if(0t)c=c.left;else if(0t?d.left=c:d.right=c;for(c.color=1;null!=c&&c!=this.d&&1==c.parent.color;)D(c)==F(D(D(c)))?(d=G(D(D(c))),1==(null==d?0:d.color)?(E(D(c),0),E(d,0),E(D(D(c)),1),c=D(D(c))):(c==G(D(c))&& -(c=D(c),I(this,c)),E(D(c),0),E(D(D(c)),1),J(this,D(D(c))))):(d=F(D(D(c))),1==(null==d?0:d.color)?(E(D(c),0),E(d,0),E(D(D(c)),1),c=D(D(c))):(c==F(D(c))&&(c=D(c),J(this,c)),E(D(c),0),E(D(D(c)),1),I(this,D(D(c)))));this.d.color=0;this.n++;return null};H.prototype.put=H.prototype.put;H.prototype.m=function(){var a=new s,b;b=this.d;if(null!=b)for(;null!=b.left;)b=b.left;if(null!==b)for(a.add(b.value);null!==(b=K(b));)a.add(b.value);return a};H.prototype.values=H.prototype.m; -function I(a,b){if(null!=b){var c=b.right;b.right=c.left;null!=c.left&&(c.left.parent=b);c.parent=b.parent;null==b.parent?a.d=c:b.parent.left==b?b.parent.left=c:b.parent.right=c;c.left=b;b.parent=c}}function J(a,b){if(null!=b){var c=b.left;b.left=c.right;null!=c.right&&(c.right.parent=b);c.parent=b.parent;null==b.parent?a.d=c:b.parent.right==b?b.parent.right=c:b.parent.left=c;c.right=b;b.parent=c}} -function K(a){if(null===a)return null;if(null!==a.right)for(var b=a.right;null!==b.left;)b=b.left;else for(b=a.parent;null!==b&&a===b.right;)a=b,b=b.parent;return b}H.prototype.size=function(){return this.n};H.prototype.size=H.prototype.size;function L(a){this.a=[];a instanceof m&&this.e(a)}g(L,B);f("javascript.util.TreeSet",L);L.prototype.a=null;L.prototype.contains=function(a){for(var b=0,c=this.a.length;b> 31) +} -},{"./dist/javascript.util-node.min.js":181}],183:[function(require,module,exports){ /** - * Takes coordinates and properties (optional) and returns a new {@link Point} feature. - * - * @module turf/point - * @category helper - * @param {number} longitude position west to east in decimal degrees - * @param {number} latitude position south to north in decimal degrees - * @param {Object} properties an Object that is used as the {@link Feature}'s - * properties - * @return {Point} a Point feature - * @example - * var pt1 = turf.point([-75.343, 39.984]); + * Encode a polygon's geometry into an array ready to be serialized + * to mapbox vector tile specified geometry data. * - * //=pt1 + * @param {Array} Rings, each being an array of [x, y] tile-space coordinates + * @return {Array} encoded geometry */ -var isArray = Array.isArray || function(arg) { - return Object.prototype.toString.call(arg) === '[object Array]'; -}; -module.exports = function(coordinates, properties) { - if (!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'); - return { - type: "Feature", - geometry: { - type: "Point", - coordinates: coordinates - }, - properties: properties || {} - }; -}; +function encodeGeometry (geometry) { + var encoded = [] + var x = 0 + var y = 0 + var rings = geometry.length + for (var r = 0; r < rings; r++) { + var ring = geometry[r] + encoded.push(command(1, 1)) // moveto + for (var i = 0; i < ring.length; i++) { + if (i === 1) { + encoded.push(command(2, ring.length - 1)) // lineto + } + var dx = ring[i].x - x + var dy = ring[i].y - y + encoded.push(zigzag(dx), zigzag(dy)) + x += dx + y += dy + } + } -},{}],184:[function(require,module,exports){ -//http://en.wikipedia.org/wiki/Delaunay_triangulation -//https://github.com/ironwallaby/delaunay -var polygon = require('turf-polygon'); -var featurecollection = require('turf-featurecollection'); + return encoded +} /** - * Takes a set of points and the name of a z-value property and - * creates a [Triangulated Irregular Network](http://en.wikipedia.org/wiki/Triangulated_irregular_network), - * or a TIN for short, returned as a collection of Polygons. These are often used - * for developing elevation contour maps or stepped heat visualizations. - * - * This triangulates the points, as well as adds properties called `a`, `b`, - * and `c` representing the value of the given `propertyName` at each of - * the points that represent the corners of the triangle. - * - * @module turf/tin - * @category interpolation - * @param {FeatureCollection} points - a GeoJSON FeatureCollection containing - * Features with {@link Point} geometries - * @param {string=} propertyName - name of the property from which to pull z values. - * This is optional: if not given, then there will be no extra data added to the derived triangles. - * @return {FeatureCollection} TIN output - * @example - * // generate some random point data - * var points = turf.random('points', 30, { - * bbox: [50, 30, 70, 50] - * }); - * //=points - * // add a random property to each point between 0 and 9 - * for (var i = 0; i < points.features.length; i++) { - * points.features[i].properties.z = ~~(Math.random() * 9); - * } - * var tin = turf.tin(points, 'z') - * for (var i = 0; i < tin.features.length; i++) { - * var properties = tin.features[i].properties; - * // roughly turn the properties of each - * // triangle into a fill color - * // so we can visualize the result - * properties.fill = '#' + properties.a + - * properties.b + properties.c; - * } - * //=tin + * Wrap a property value according to its type. The returned object + * is of the form { xxxx_value: primitiveValue }, which is what the generated + * protobuf serializer expects. */ -module.exports = function(points, z) { - //break down points - return featurecollection(triangulate(points.features.map(function(p) { - var point = { - x: p.geometry.coordinates[0], - y: p.geometry.coordinates[1] - }; - if (z) point.z = p.properties[z]; - return point; - })).map(function(triangle) { - return polygon([[ - [triangle.a.x, triangle.a.y], - [triangle.b.x, triangle.b.y], - [triangle.c.x, triangle.c.y], - [triangle.a.x, triangle.a.y] - ]], { - a: triangle.a.z, - b: triangle.b.z, - c: triangle.c.z - }); - })); -}; - -function Triangle(a, b, c) { - this.a = a; - this.b = b; - this.c = c; - - var A = b.x - a.x, - B = b.y - a.y, - C = c.x - a.x, - D = c.y - a.y, - E = A * (a.x + b.x) + B * (a.y + b.y), - F = C * (a.x + c.x) + D * (a.y + c.y), - G = 2 * (A * (c.y - b.y) - B * (c.x - b.x)), - minx, miny, dx, dy; - - // If the points of the triangle are collinear, then just find the - // extremes and use the midpoint as the center of the circumcircle. - if (Math.abs(G) < 0.000001) { - minx = Math.min(a.x, b.x, c.x); - miny = Math.min(a.y, b.y, c.y); - dx = (Math.max(a.x, b.x, c.x) - minx) * 0.5; - dy = (Math.max(a.y, b.y, c.y) - miny) * 0.5; - - this.x = minx + dx; - this.y = miny + dy; - this.r = dx * dx + dy * dy; +function wrapValue (value) { + var result + var type = typeof value + if (type === 'string') { + result = { string_value: value } + } else if (type === 'boolean') { + result = { bool_value: value } + } else if (type === 'number') { + if (value % 1 !== 0) { + result = { double_value: value } + } else if (value < 0) { + result = { sint_value: value } + } else { + result = { uint_value: value } + } } else { - this.x = (D * E - B * F) / G; - this.y = (A * F - C * E) / G; - dx = this.x - a.x; - dy = this.y - a.y; - this.r = dx * dx + dy * dy; + value = JSON.stringify(value) + result = { string_value: value } } + + result.key = type + ':' + value + return result } -function byX(a, b) { - return b.x - a.x; +},{"./lib/geojson_wrapper":217,"./vector-tile-pb":220,"pbf":219}],217:[function(require,module,exports){ +'use strict' + +var Point = require('point-geometry') +var VectorTileFeature = require('vector-tile').VectorTileFeature + +module.exports = GeoJSONWrapper + +// conform to vectortile api +function GeoJSONWrapper (features) { + this.features = features + this.length = features.length } -function dedup(edges) { - var j = edges.length, - a, b, i, m, n; +GeoJSONWrapper.prototype.feature = function (i) { + return new FeatureWrapper(this.features[i]) +} - outer: - while (j) { - b = edges[--j]; - a = edges[--j]; - i = j; - while (i) { - n = edges[--i]; - m = edges[--i]; - if ((a === m && b === n) || (a === n && b === m)) { - edges.splice(j, 2); - edges.splice(i, 2); - j -= 2; - continue outer; - } +function FeatureWrapper (feature) { + this.id = typeof feature.id === 'number' ? feature.id : undefined + this.type = feature.type + this.rawGeometry = feature.type === 1 ? [feature.geometry] : feature.geometry + this.properties = feature.tags + this.extent = 4096 +} + +FeatureWrapper.prototype.loadGeometry = function () { + var rings = this.rawGeometry + this.geometry = [] + + for (var i = 0; i < rings.length; i++) { + var ring = rings[i] + var newRing = [] + for (var j = 0; j < ring.length; j++) { + newRing.push(new Point(ring[j][0], ring[j][1])) } + this.geometry.push(newRing) } + return this.geometry } -function triangulate(vertices) { - // Bail if there aren't enough vertices to form any triangles. - if (vertices.length < 3) - return []; +FeatureWrapper.prototype.bbox = function () { + if (!this.geometry) this.loadGeometry() - // Ensure the vertex array is in order of descending X coordinate - // (which is needed to ensure a subquadratic runtime), and then find - // the bounding box around the points. - vertices.sort(byX); + var rings = this.geometry + var x1 = Infinity + var x2 = -Infinity + var y1 = Infinity + var y2 = -Infinity - var i = vertices.length - 1, - xmin = vertices[i].x, - xmax = vertices[0].x, - ymin = vertices[i].y, - ymax = ymin; + for (var i = 0; i < rings.length; i++) { + var ring = rings[i] - while (i--) { - if (vertices[i].y < ymin) - ymin = vertices[i].y; - if (vertices[i].y > ymax) - ymax = vertices[i].y; + for (var j = 0; j < ring.length; j++) { + var coord = ring[j] + + x1 = Math.min(x1, coord.x) + x2 = Math.max(x2, coord.x) + y1 = Math.min(y1, coord.y) + y2 = Math.max(y2, coord.y) + } } - //Find a supertriangle, which is a triangle that surrounds all the - //vertices. This is used like something of a sentinel value to remove - //cases in the main algorithm, and is removed before we return any - // results. - - // Once found, put it in the "open" list. (The "open" list is for - // triangles who may still need to be considered; the "closed" list is - // for triangles which do not.) - var dx = xmax - xmin, - dy = ymax - ymin, - dmax = (dx > dy) ? dx : dy, - xmid = (xmax + xmin) * 0.5, - ymid = (ymax + ymin) * 0.5, - open = [ - new Triangle({ - x: xmid - 20 * dmax, - y: ymid - dmax, - __sentinel: true - }, - { - x: xmid, - y: ymid + 20 * dmax, - __sentinel: true - }, - { - x: xmid + 20 * dmax, - y: ymid - dmax, - __sentinel: true - } - )], - closed = [], - edges = [], - j, a, b; + return [x1, y1, x2, y2] +} - // Incrementally add each vertex to the mesh. - i = vertices.length; - while (i--) { - // For each open triangle, check to see if the current point is - // inside it's circumcircle. If it is, remove the triangle and add - // it's edges to an edge list. - edges.length = 0; - j = open.length; - while (j--) { - // If this point is to the right of this triangle's circumcircle, - // then this triangle should never get checked again. Remove it - // from the open list, add it to the closed list, and skip. - dx = vertices[i].x - open[j].x; - if (dx > 0 && dx * dx > open[j].r) { - closed.push(open[j]); - open.splice(j, 1); - continue; - } +FeatureWrapper.prototype.toGeoJSON = VectorTileFeature.prototype.toGeoJSON - // If not, skip this triangle. - dy = vertices[i].y - open[j].y; - if (dx * dx + dy * dy > open[j].r) - continue; +},{"point-geometry":196,"vector-tile":212}],218:[function(require,module,exports){ +arguments[4][191][0].apply(exports,arguments) +},{"dup":191,"ieee754":40}],219:[function(require,module,exports){ +arguments[4][192][0].apply(exports,arguments) +},{"./buffer":218,"dup":192}],220:[function(require,module,exports){ +'use strict'; - // Remove the triangle and add it's edges to the edge list. - edges.push( - open[j].a, open[j].b, - open[j].b, open[j].c, - open[j].c, open[j].a - ); - open.splice(j, 1); - } +// tile ======================================== - // Remove any doubled edges. - dedup(edges); +var tile = exports.tile = {read: readTile, write: writeTile}; - // Add a new triangle for each edge. - j = edges.length; - while (j) { - b = edges[--j]; - a = edges[--j]; - open.push(new Triangle(a, b, vertices[i])); - } - } +tile.GeomType = { + "Unknown": 0, + "Point": 1, + "LineString": 2, + "Polygon": 3 +}; - // Copy any remaining open triangles to the closed list, and then - // remove any triangles that share a vertex with the supertriangle. - Array.prototype.push.apply(closed, open); +function readTile(pbf, end) { + return pbf.readFields(readTileField, {"layers": []}, end); +} - i = closed.length; - while (i--) - if (closed[i].a.__sentinel || - closed[i].b.__sentinel || - closed[i].c.__sentinel) - closed.splice(i, 1); +function readTileField(tag, tile, pbf) { + if (tag === 3) tile.layers.push(readLayer(pbf, pbf.readVarint() + pbf.pos)); +} - return closed; +function writeTile(tile, pbf) { + var i; + if (tile.layers !== undefined) for (i = 0; i < tile.layers.length; i++) pbf.writeMessage(3, writeLayer, tile.layers[i]); } -},{"turf-featurecollection":185,"turf-polygon":186}],185:[function(require,module,exports){ -/** - * Takes one or more {@link Feature|Features} and creates a {@link FeatureCollection} - * - * @module turf/featurecollection - * @category helper - * @param {Feature} features input Features - * @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 fc = turf.featurecollection(features); - * - * //=fc - */ -module.exports = function(features){ - return { - type: "FeatureCollection", - features: features - }; -}; +// value ======================================== -},{}],186:[function(require,module,exports){ -/** - * Takes an array of LinearRings and optionally an {@link Object} with properties and returns a GeoJSON {@link Polygon} feature. - * - * @module turf/polygon - * @category helper - * @param {Array>} rings an array of LinearRings - * @param {Object} properties an optional properties object - * @return {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 - */ -module.exports = function(coordinates, properties){ +tile.value = {read: readValue, write: writeValue}; - if (coordinates === null) throw new Error('No coordinates passed'); +function readValue(pbf, end) { + return pbf.readFields(readValueField, {}, end); +} - for (var i = 0; i < coordinates.length; i++) { - var ring = coordinates[i]; - for (var j = 0; j < ring[ring.length - 1].length; j++) { - if (ring.length < 4) { - throw new Error('Each LinearRing of a Polygon must have 4 or more Positions.'); - } - if (ring[ring.length - 1][j] !== ring[0][j]) { - throw new Error('First and last Position are not equivalent.'); - } - } - } +function readValueField(tag, value, pbf) { + if (tag === 1) value.string_value = pbf.readString(); + else if (tag === 2) value.float_value = pbf.readFloat(); + else if (tag === 3) value.double_value = pbf.readDouble(); + else if (tag === 4) value.int_value = pbf.readVarint(); + else if (tag === 5) value.uint_value = pbf.readVarint(); + else if (tag === 6) value.sint_value = pbf.readSVarint(); + else if (tag === 7) value.bool_value = pbf.readBoolean(); +} - var polygon = { - "type": "Feature", - "geometry": { - "type": "Polygon", - "coordinates": coordinates - }, - "properties": properties - }; +function writeValue(value, pbf) { + if (value.string_value !== undefined) pbf.writeStringField(1, value.string_value); + if (value.float_value !== undefined) pbf.writeFloatField(2, value.float_value); + if (value.double_value !== undefined) pbf.writeDoubleField(3, value.double_value); + if (value.int_value !== undefined) pbf.writeVarintField(4, value.int_value); + if (value.uint_value !== undefined) pbf.writeVarintField(5, value.uint_value); + if (value.sint_value !== undefined) pbf.writeSVarintField(6, value.sint_value); + if (value.bool_value !== undefined) pbf.writeBooleanField(7, value.bool_value); +} - if (!polygon.properties) { - polygon.properties = {}; - } +// feature ======================================== - return polygon; -}; +tile.feature = {read: readFeature, write: writeFeature}; -},{}],187:[function(require,module,exports){ -arguments[4][172][0].apply(exports,arguments) -},{"dup":172}],188:[function(require,module,exports){ -var concave = require('turf-concave'); -var geojsonhint = require('geojsonhint'); +function readFeature(pbf, end) { + var feature = pbf.readFields(readFeatureField, {}, end); + if (feature.type === undefined) feature.type = "Unknown"; + return feature; +} +function readFeatureField(tag, feature, pbf) { + if (tag === 1) feature.id = pbf.readVarint(); + else if (tag === 2) feature.tags = pbf.readPackedVarint(); + else if (tag === 3) feature.type = pbf.readVarint(); + else if (tag === 4) feature.geometry = pbf.readPackedVarint(); +} -module.exports = function(self) { - self.addEventListener('message', function(ev) { - var dataUrl = ev.data[0]; - self.makeRequest(dataUrl); - }); +function writeFeature(feature, pbf) { + if (feature.id !== undefined) pbf.writeVarintField(1, feature.id); + if (feature.tags !== undefined) pbf.writePackedVarint(2, feature.tags); + if (feature.type !== undefined) pbf.writeVarintField(3, feature.type); + if (feature.geometry !== undefined) pbf.writePackedVarint(4, feature.geometry); +} - self.makeRequest = function(url) { - var req = new XMLHttpRequest(); - req.addEventListener('load', self.validateData); - req.addEventListener('error', self.transferFailed); - req.open('GET', url); - req.send(); - }; +// layer ======================================== - self.validateData = function() { - var errors = geojsonhint.hint(this.responseText); - if (errors.len > 0) { - self.postMessage(['Errors', errors.join(', ') ]); - } else { - self.turfIt(this.responseText); +tile.layer = {read: readLayer, write: writeLayer}; + +function readLayer(pbf, end) { + return pbf.readFields(readLayerField, {"features": [], "keys": [], "values": []}, end); +} + +function readLayerField(tag, layer, pbf) { + if (tag === 15) layer.version = pbf.readVarint(); + else if (tag === 1) layer.name = pbf.readString(); + else if (tag === 2) layer.features.push(readFeature(pbf, pbf.readVarint() + pbf.pos)); + else if (tag === 3) layer.keys.push(pbf.readString()); + else if (tag === 4) layer.values.push(readValue(pbf, pbf.readVarint() + pbf.pos)); + else if (tag === 5) layer.extent = pbf.readVarint(); +} + +function writeLayer(layer, pbf) { + if (layer.version !== undefined) pbf.writeVarintField(15, layer.version); + if (layer.name !== undefined) pbf.writeStringField(1, layer.name); + var i; + if (layer.features !== undefined) for (i = 0; i < layer.features.length; i++) pbf.writeMessage(2, writeFeature, layer.features[i]); + if (layer.keys !== undefined) for (i = 0; i < layer.keys.length; i++) pbf.writeStringField(3, layer.keys[i]); + if (layer.values !== undefined) for (i = 0; i < layer.values.length; i++) pbf.writeMessage(4, writeValue, layer.values[i]); + if (layer.extent !== undefined) pbf.writeVarintField(5, layer.extent); +} + +},{}],221:[function(require,module,exports){ +var bundleFn = arguments[3]; +var sources = arguments[4]; +var cache = arguments[5]; + +var stringify = JSON.stringify; + +module.exports = function (fn, options) { + var wkey; + var cacheKeys = Object.keys(cache); + + for (var i = 0, l = cacheKeys.length; i < l; i++) { + var key = cacheKeys[i]; + var exp = cache[key].exports; + // Using babel as a transpiler to use esmodule, the export will always + // be an object with the default export as a property of it. To ensure + // the existing api and babel esmodule exports are both supported we + // check for both + if (exp === fn || exp && exp.default === fn) { + wkey = key; + break; + } } - }; - self.transferFailed = function() { - self.postMessage(['Error', this.responseText]); - }; + if (!wkey) { + wkey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16); + var wcache = {}; + for (var i = 0, l = cacheKeys.length; i < l; i++) { + var key = cacheKeys[i]; + wcache[key] = key; + } + sources[wkey] = [ + Function(['require','module','exports'], '(' + fn + ')(self)'), + wcache + ]; + } + var skey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16); - self.turfIt = function(data) { - var results = concave(JSON.parse(data), 1, 'miles'); - self.postMessage(['Done', results]); - }; -}; + var scache = {}; scache[wkey] = wkey; + sources[skey] = [ + Function(['require'], ( + // try to call default if defined to also support babel esmodule + // exports + 'var f = require(' + stringify(wkey) + ');' + + '(f.default ? f.default : f)(self);' + )), + scache + ]; + + var workerSources = {}; + resolveSources(skey); + + function resolveSources(key) { + workerSources[key] = true; + + for (var depPath in sources[key][1]) { + var depKey = sources[key][1][depPath]; + if (!workerSources[depKey]) { + resolveSources(depKey); + } + } + } + + var src = '(' + bundleFn + ')({' + + Object.keys(workerSources).map(function (key) { + return stringify(key) + ':[' + + sources[key][0] + + ',' + stringify(sources[key][1]) + ']' + ; + }).join(',') + + '},{},[' + stringify(skey) + '])' + ; + + var URL = window.URL || window.webkitURL || window.mozURL || window.msURL; + + var blob = new Blob([src], { type: 'text/javascript' }); + if (options && options.bare) { return blob; } + var workerUrl = URL.createObjectURL(blob); + var worker = new Worker(workerUrl); + worker.objectURL = workerUrl; + return worker; +}; + +},{}],222:[function(require,module,exports){ +module.exports.RADIUS = 6378137; +module.exports.FLATTENING = 1/298.257223563; +module.exports.POLAR_RADIUS = 6356752.3142; + +},{}],223:[function(require,module,exports){ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (factory((global.WhooTS = global.WhooTS || {}))); +}(this, function (exports) { + +/** + * getURL + * + * @param {String} baseUrl Base url of the WMS server + * @param {String} layer Layer name + * @param {Number} x Tile coordinate x + * @param {Number} y Tile coordinate y + * @param {Number} z Tile zoom + * @param {Object} [options] + * @param {String} [options.format='image/png'] + * @param {String} [options.service='WMS'] + * @param {String} [options.version='1.1.1'] + * @param {String} [options.request='GetMap'] + * @param {String} [options.srs='EPSG:3857'] + * @param {Number} [options.width='256'] + * @param {Number} [options.height='256'] + * @returns {String} url + * @example + * var baseUrl = 'http://geodata.state.nj.us/imagerywms/Natural2015'; + * var layer = 'Natural2015'; + * var url = whoots.getURL(baseUrl, layer, 154308, 197167, 19); + */ +function getURL(baseUrl, layer, x, y, z, options) { + options = options || {}; + + var url = baseUrl + '?' + [ + 'bbox=' + getTileBBox(x, y, z), + 'format=' + (options.format || 'image/png'), + 'service=' + (options.service || 'WMS'), + 'version=' + (options.version || '1.1.1'), + 'request=' + (options.request || 'GetMap'), + 'srs=' + (options.srs || 'EPSG:3857'), + 'width=' + (options.width || 256), + 'height=' + (options.height || 256), + 'layers=' + layer + ].join('&'); + + return url; +} + + +/** + * getTileBBox + * + * @param {Number} x Tile coordinate x + * @param {Number} y Tile coordinate y + * @param {Number} z Tile zoom + * @returns {String} String of the bounding box + */ +function getTileBBox(x, y, z) { + // for Google/OSM tile scheme we need to alter the y + y = (Math.pow(2, z) - y - 1); + + var min = getMercCoords(x * 256, y * 256, z), + max = getMercCoords((x + 1) * 256, (y + 1) * 256, z); + + return min[0] + ',' + min[1] + ',' + max[0] + ',' + max[1]; +} + + +/** + * getMercCoords + * + * @param {Number} x Pixel coordinate x + * @param {Number} y Pixel coordinate y + * @param {Number} z Tile zoom + * @returns {Array} [x, y] + */ +function getMercCoords(x, y, z) { + var resolution = (2 * Math.PI * 6378137 / 256) / Math.pow(2, z), + merc_x = (x * resolution - 2 * Math.PI * 6378137 / 2.0), + merc_y = (y * resolution - 2 * Math.PI * 6378137 / 2.0); + + return [merc_x, merc_y]; +} -},{"geojsonhint":13,"turf-concave":173}]},{},[12]); +exports.getURL = getURL; +exports.getTileBBox = getTileBBox; +exports.getMercCoords = getMercCoords; + +Object.defineProperty(exports, '__esModule', { value: true }); + +})); +},{}],224:[function(require,module,exports){ +var concave = require('@turf/concave'); +var geojsonhint = require('geojsonhint'); +var geobuf = require('geobuf'); +var Pbf = require('pbf'); + +module.exports = function(self) { + self.addEventListener('message', function(ev) { + var dataUrl = ev.data[0]; + self.makeRequest(dataUrl); + }); + + self.makeRequest = function(url) { + var req = new XMLHttpRequest(); + req.addEventListener('load', self.validateData); + req.addEventListener('error', self.transferFailed); + req.open('GET', url); + req.send(); + }; + + self.validateData = function() { + var errors = geojsonhint.hint(this.responseText); + if (errors.len > 0) { + self.postMessage(['Errors', errors.join(', ') ]); + } else { + self.turfIt(this.responseText); + } + }; + + self.transferFailed = function() { + self.postMessage(['Error', this.responseText]); + }; + + self.turfIt = function(data) { + var results = concave(JSON.parse(data), 0.75, 'miles'); + var buf = geobuf.encode(results, new Pbf()); + self.postMessage(['Done', buf]); + }; +}; + +},{"@turf/concave":2,"geobuf":15,"geojsonhint":26,"pbf":195}]},{},[1]); diff --git a/index.html b/index.html index 28cba8d..e6411da 100644 --- a/index.html +++ b/index.html @@ -4,8 +4,8 @@ - - + + +
diff --git a/main.js b/main.js index 0731bea..26d4db7 100644 --- a/main.js +++ b/main.js @@ -1,16 +1,14 @@ var work = require('webworkify'); var mapboxgl = require('mapbox-gl'); -var concave = require('turf-concave'); +var concave = require('@turf/concave'); var geojsonhint = require('geojsonhint'); var geobuf = require('geobuf'); var Pbf = require('pbf'); var w = work(require('./worker.js')); w.addEventListener('message', function(ev) { - console.log(ev.data); - var gj = geobuf.decode(ev.data[1]); - console.log(gj); - turfResult.setData(gj); + var gj = geobuf.decode(new Pbf(ev.data[1])); + map.getSource('results').setData(gj); }); w.addEventListener('error', function(err) { @@ -26,22 +24,27 @@ var map = new mapboxgl.Map({ zoom: 10 }); -var dataUrl = 'assets/hydrants.geojson'; - -var hydrants = new mapboxgl.GeoJSONSource({ - data: dataUrl -}); +var emptyGeoJson = { + type: 'FeatureCollection', + features: [] +}; -var turfResult = new mapboxgl.GeoJSONSource({}); +var dataUrl = 'assets/hydrants.geojson'; map.on('style.load', function() { console.log('style loaded'); - map.addSource('points', hydrants); + map.addSource('points', { + type: 'geojson', + data: dataUrl + }); - map.addSource('results', turfResult); + map.addSource('results', { + type: 'geojson', + data: emptyGeoJson + }); map.addLayer({ - 'id': 'hydrants', + 'id': 'points', 'type': 'circle', 'source': 'points' }); @@ -90,9 +93,9 @@ function addButton(name, id) { function turfSync() { - turfResult.setData(''); + map.getSource('results').setData(emptyGeoJson); var absUrl = window.location + dataUrl; - makeRequest(absUrl); + makeRequest(dataUrl); } function makeRequest(url) { @@ -117,12 +120,12 @@ function transferFailed() { } function turfIt(data) { - var results = concave(JSON.parse(data), 1, 'miles'); - turfResult.setData(results); + var results = concave(JSON.parse(data), 0.75, 'miles'); + map.getSource('results').setData(results); } function turfAsync() { - turfResult.setData(''); + map.getSource('results').setData(emptyGeoJson); var absUrl = window.location + dataUrl; w.postMessage([absUrl]); } diff --git a/package.json b/package.json index 0a2ba1b..366a140 100644 --- a/package.json +++ b/package.json @@ -4,19 +4,22 @@ "description": "Demonstrating how to use Turf.js with web workers to run geoprocesses asynchronously", "main": "main.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "start": "budo main.js --serve bundle.js", + "build": "browserify main.js > bundle.js" }, "author": "Nick Peihl ", "license": "ISC", "dependencies": { - "geobuf": "^2.0.0", + "@turf/concave": "^3.5.2", + "geobuf": "^3.0.0", "geojsonhint": "^1.2.0", - "mapbox-gl": "^0.14.1", - "pbf": "^1.3.5", - "turf-concave": "^1.1.3", - "webworkify": "^1.1.0" + "mapbox-gl": "^0.25.1", + "pbf": "^3.0.2", + "webworkify": "^1.4.0" }, "devDependencies": { - "browserify": "^13.0.0" + "browserify": "^13.1.0", + "budo": "^9.2.1" } } diff --git a/worker.js b/worker.js index d80e477..727e14f 100644 --- a/worker.js +++ b/worker.js @@ -1,10 +1,8 @@ -var concave = require('turf-concave'); +var concave = require('@turf/concave'); var geojsonhint = require('geojsonhint'); var geobuf = require('geobuf'); var Pbf = require('pbf'); -debugger; - module.exports = function(self) { self.addEventListener('message', function(ev) { var dataUrl = ev.data[0]; @@ -33,16 +31,8 @@ module.exports = function(self) { }; self.turfIt = function(data) { - var results = concave(JSON.parse(data), 1, 'miles'); - var pbf = new Pbf(geobuf.encode(results, new Pbf())); - /* The pbf does not contain the readFields method when called via - the web worker. However, I can set a breakpoint on the line below, - then rewrite the above line using a different variable (e.g. pbf2). - The pbf2 variable does contain the readFields method. I believe this - is due to the scope of the pbf buffer existing in the browser, but not - in the web worker. Possibly releated to this issue - (https://github.com/substack/webworkify/issues/14). - */ - self.postMessage(['Done', pbf]); + var results = concave(JSON.parse(data), 0.75, 'miles'); + var buf = geobuf.encode(results, new Pbf()); + self.postMessage(['Done', buf]); }; };