Files
conservatorio-tomadini/media/com_phocagallery/js/leaflet-omnivore/leaflet-omnivore.js
2024-12-17 17:34:10 +01:00

3278 lines
102 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var o;"undefined"!=typeof window?o=window:"undefined"!=typeof global?o=global:"undefined"!=typeof self&&(o=self),o.omnivore=e()}}(function(){var define,module,exports;return (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);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
var xhr = _dereq_('corslite'),
csv2geojson = _dereq_('csv2geojson'),
wellknown = _dereq_('wellknown'),
topojson = _dereq_('topojson'),
toGeoJSON = _dereq_('togeojson');
module.exports.geojson = geojsonLoad;
module.exports.topojson = topojsonLoad;
module.exports.topojson.parse = topojsonParse;
module.exports.csv = csvLoad;
module.exports.csv.parse = csvParse;
module.exports.gpx = gpxLoad;
module.exports.gpx.parse = gpxParse;
module.exports.kml = kmlLoad;
module.exports.kml.parse = kmlParse;
module.exports.wkt = wktLoad;
module.exports.wkt.parse = wktParse;
function addData(l, d) {
if ('addData' in l) l.addData(d);
if ('setGeoJSON' in l) l.setGeoJSON(d);
}
/**
* Load a [GeoJSON](http://geojson.org/) document into a layer and return the layer.
*
* @param {string} url
* @param {object} options
* @param {object} customLayer
* @returns {object}
*/
function geojsonLoad(url, options, customLayer) {
var layer = customLayer || L.geoJson();
xhr(url, function(err, response) {
if (err) return layer.fire('error', { error: err });
addData(layer, JSON.parse(response.responseText));
layer.fire('ready');
});
return layer;
}
/**
* Load a [TopoJSON](https://github.com/mbostock/topojson) document into a layer and return the layer.
*
* @param {string} url
* @param {object} options
* @param {object} customLayer
* @returns {object}
*/
function topojsonLoad(url, options, customLayer) {
var layer = customLayer || L.geoJson();
xhr(url, onload);
function onload(err, response) {
if (err) return layer.fire('error', { error: err });
addData(layer, topojsonParse(response.responseText));
layer.fire('ready');
}
return layer;
}
/**
* Load a CSV document into a layer and return the layer.
*
* @param {string} url
* @param {object} options
* @param {object} customLayer
* @returns {object}
*/
function csvLoad(url, options, customLayer) {
var layer = customLayer || L.geoJson();
xhr(url, onload);
function onload(err, response) {
var error;
if (err) return layer.fire('error', { error: err });
function avoidReady() {
error = true;
}
layer.on('error', avoidReady);
csvParse(response.responseText, options, layer);
layer.off('error', avoidReady);
if (!error) layer.fire('ready');
}
return layer;
}
/**
* Load a GPX document into a layer and return the layer.
*
* @param {string} url
* @param {object} options
* @param {object} customLayer
* @returns {object}
*/
function gpxLoad(url, options, customLayer) {
var layer = customLayer || L.geoJson();
xhr(url, onload);
function onload(err, response) {
var error;
if (err) return layer.fire('error', { error: err });
function avoidReady() {
error = true;
}
layer.on('error', avoidReady);
gpxParse(response.responseXML || response.responseText, options, layer);
layer.off('error', avoidReady);
if (!error) layer.fire('ready');
}
return layer;
}
/**
* Load a [KML](https://developers.google.com/kml/documentation/) document into a layer and return the layer.
*
* @param {string} url
* @param {object} options
* @param {object} customLayer
* @returns {object}
*/
function kmlLoad(url, options, customLayer) {
var layer = L.geoJson();
xhr(url, onload);
function onload(err, response) {
var error;
if (err) return layer.fire('error', { error: err });
function avoidReady() {
error = true;
}
layer.on('error', avoidReady);
kmlParse(response.responseXML || response.responseText, options, layer);
layer.off('error', avoidReady);
if (!error) layer.fire('ready');
}
return layer;
}
/**
* Load a WKT (Well Known Text) string into a layer and return the layer
*
* @param {string} url
* @param {object} options
* @param {object} customLayer
* @returns {object}
*/
function wktLoad(url, options, customLayer) {
var layer = customLayer || L.geoJson();
xhr(url, onload);
function onload(err, response) {
if (err) return layer.fire('error', { error: err });
wktParse(response.responseText, options, layer);
layer.fire('ready');
}
return layer;
}
function topojsonParse(data) {
var o = typeof data === 'string' ?
JSON.parse(data) : data;
var features = [];
for (var i in o.objects) {
var ft = topojson.feature(o, o.objects[i]);
if (ft.features) features = features.concat(ft.features);
else features = features.concat([ft]);
}
return features;
}
function csvParse(csv, options, layer) {
layer = layer || L.geoJson();
options = options || {};
csv2geojson.csv2geojson(csv, options, onparse);
function onparse(err, geojson) {
if (err) return layer.fire('error', { error: err });
addData(layer, geojson);
}
return layer;
}
function gpxParse(gpx, options, layer) {
var xml = parseXML(gpx);
if (!xml) return layer.fire('error', {
error: 'Could not parse GPX'
});
layer = layer || L.geoJson();
var geojson = toGeoJSON.gpx(xml);
addData(layer, geojson);
return layer;
}
function kmlParse(gpx, options, layer) {
var xml = parseXML(gpx);
if (!xml) return layer.fire('error', {
error: 'Could not parse GPX'
});
layer = layer || L.geoJson();
var geojson = toGeoJSON.kml(xml);
addData(layer, geojson);
return layer;
}
function wktParse(wkt, options, layer) {
layer = layer || L.geoJson();
var geojson = wellknown(wkt);
addData(layer, geojson);
return layer;
}
function parseXML(str) {
if (typeof str === 'string') {
return (new DOMParser()).parseFromString(str, 'text/xml');
} else {
return str;
}
}
},{"corslite":5,"csv2geojson":6,"togeojson":9,"topojson":10,"wellknown":38}],2:[function(_dereq_,module,exports){
},{}],3:[function(_dereq_,module,exports){
module.exports=_dereq_(2)
},{}],4:[function(_dereq_,module,exports){
// shim for using process in browser
var process = module.exports = {};
process.nextTick = (function () {
var canSetImmediate = typeof window !== 'undefined'
&& window.setImmediate;
var canPost = typeof window !== 'undefined'
&& window.postMessage && window.addEventListener
;
if (canSetImmediate) {
return function (f) { return window.setImmediate(f) };
}
if (canPost) {
var queue = [];
window.addEventListener('message', function (ev) {
var source = ev.source;
if ((source === window || source === null) && ev.data === 'process-tick') {
ev.stopPropagation();
if (queue.length > 0) {
var fn = queue.shift();
fn();
}
}
}, true);
return function nextTick(fn) {
queue.push(fn);
window.postMessage('process-tick', '*');
};
}
return function nextTick(fn) {
setTimeout(fn, 0);
};
})();
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.binding = function (name) {
throw new Error('process.binding is not supported');
}
// TODO(shtylman)
process.cwd = function () { return '/' };
process.chdir = function (dir) {
throw new Error('process.chdir is not supported');
};
},{}],5:[function(_dereq_,module,exports){
function xhr(url, callback, cors) {
var sent = false;
if (typeof window.XMLHttpRequest === 'undefined') {
return callback(Error('Browser not supported'));
}
if (typeof cors === 'undefined') {
var m = url.match(/^\s*https?:\/\/[^\/]*/);
cors = m && (m[0] !== location.protocol + '//' + location.domain +
(location.port ? ':' + location.port : ''));
}
var x;
function isSuccessful(status) {
return status >= 200 && status < 300 || status === 304;
}
if (cors && (
// IE7-9 Quirks & Compatibility
typeof window.XDomainRequest === 'object' ||
// IE9 Standards mode
typeof window.XDomainRequest === 'function'
)) {
// IE8-10
x = new window.XDomainRequest();
// Ensure callback is never called synchronously, i.e., before
// x.send() returns (this has been observed in the wild).
// See https://github.com/mapbox/mapbox.js/issues/472
var original = callback;
callback = function() {
if (sent) {
original.apply(this, arguments);
} else {
var that = this, args = arguments;
setTimeout(function() {
original.apply(that, args);
}, 0);
}
}
} else {
x = new window.XMLHttpRequest();
}
function loaded() {
if (
// XDomainRequest
x.status === undefined ||
// modern browsers
isSuccessful(x.status)) callback.call(x, null, x);
else callback.call(x, x, null);
}
// Both `onreadystatechange` and `onload` can fire. `onreadystatechange`
// has [been supported for longer](http://stackoverflow.com/a/9181508/229001).
if ('onload' in x) {
x.onload = loaded;
} else {
x.onreadystatechange = function readystate() {
if (x.readyState === 4) {
loaded();
}
};
}
// Call the callback with the XMLHttpRequest object as an error and prevent
// it from ever being called again by reassigning it to `noop`
x.onerror = function error(evt) {
// XDomainRequest provides no evt parameter
callback.call(this, evt || true, null);
callback = function() { };
};
// IE9 must have onprogress be set to a unique function.
x.onprogress = function() { };
x.ontimeout = function(evt) {
callback.call(this, evt, null);
callback = function() { };
};
x.onabort = function(evt) {
callback.call(this, evt, null);
callback = function() { };
};
// GET is the only supported HTTP Verb by XDomainRequest and is the
// only one supported here.
x.open('GET', url, true);
// Send the request. Sending data is not supported.
x.send(null);
sent = true;
return x;
}
if (typeof module !== 'undefined') module.exports = xhr;
},{}],6:[function(_dereq_,module,exports){
var dsv = _dereq_('dsv'),
sexagesimal = _dereq_('sexagesimal');
function isLat(f) { return !!f.match(/(Lat)(itude)?/gi); }
function isLon(f) { return !!f.match(/(L)(on|ng)(gitude)?/i); }
function keyCount(o) {
return (typeof o == 'object') ? Object.keys(o).length : 0;
}
function autoDelimiter(x) {
var delimiters = [',', ';', '\t', '|'];
var results = [];
delimiters.forEach(function(delimiter) {
var res = dsv(delimiter).parse(x);
if (res.length >= 1) {
var count = keyCount(res[0]);
for (var i = 0; i < res.length; i++) {
if (keyCount(res[i]) !== count) return;
}
results.push({
delimiter: delimiter,
arity: Object.keys(res[0]).length,
});
}
});
if (results.length) {
return results.sort(function(a, b) {
return b.arity - a.arity;
})[0].delimiter;
} else {
return null;
}
}
function auto(x) {
var delimiter = autoDelimiter(x);
if (!delimiter) return null;
return dsv(delimiter).parse(x);
}
function csv2geojson(x, options, callback) {
if (!callback) {
callback = options;
options = {};
}
options.delimiter = options.delimiter || ',';
var latfield = options.latfield || '',
lonfield = options.lonfield || '';
var features = [],
featurecollection = { type: 'FeatureCollection', features: features };
if (options.delimiter === 'auto' && typeof x == 'string') {
options.delimiter = autoDelimiter(x);
if (!options.delimiter) return callback({
type: 'Error',
message: 'Could not autodetect delimiter'
});
}
var parsed = (typeof x == 'string') ? dsv(options.delimiter).parse(x) : x;
if (!parsed.length) return callback(null, featurecollection);
if (!latfield || !lonfield) {
for (var f in parsed[0]) {
if (!latfield && isLat(f)) latfield = f;
if (!lonfield && isLon(f)) lonfield = f;
}
if (!latfield || !lonfield) {
var fields = [];
for (var k in parsed[0]) fields.push(k);
return callback({
type: 'Error',
message: 'Latitude and longitude fields not present',
data: parsed,
fields: fields
});
}
}
var errors = [];
for (var i = 0; i < parsed.length; i++) {
if (parsed[i][lonfield] !== undefined &&
parsed[i][lonfield] !== undefined) {
var lonk = parsed[i][lonfield],
latk = parsed[i][latfield],
lonf, latf,
a;
a = sexagesimal(lonk, 'EW');
if (a) lonk = a;
a = sexagesimal(latk, 'NS');
if (a) latk = a;
lonf = parseFloat(lonk);
latf = parseFloat(latk);
if (isNaN(lonf) ||
isNaN(latf)) {
errors.push({
message: 'A row contained an invalid value for latitude or longitude',
row: parsed[i]
});
} else {
if (!options.includeLatLon) {
delete parsed[i][lonfield];
delete parsed[i][latfield];
}
features.push({
type: 'Feature',
properties: parsed[i],
geometry: {
type: 'Point',
coordinates: [
parseFloat(lonf),
parseFloat(latf)
]
}
});
}
}
}
callback(errors.length ? errors: null, featurecollection);
}
function toLine(gj) {
var features = gj.features;
var line = {
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: []
}
};
for (var i = 0; i < features.length; i++) {
line.geometry.coordinates.push(features[i].geometry.coordinates);
}
line.properties = features[0].properties;
return {
type: 'FeatureCollection',
features: [line]
};
}
function toPolygon(gj) {
var features = gj.features;
var poly = {
type: 'Feature',
geometry: {
type: 'Polygon',
coordinates: [[]]
}
};
for (var i = 0; i < features.length; i++) {
poly.geometry.coordinates[0].push(features[i].geometry.coordinates);
}
poly.properties = features[0].properties;
return {
type: 'FeatureCollection',
features: [poly]
};
}
module.exports = {
isLon: isLon,
isLat: isLat,
csv: dsv.csv.parse,
tsv: dsv.tsv.parse,
dsv: dsv,
auto: auto,
csv2geojson: csv2geojson,
toLine: toLine,
toPolygon: toPolygon
};
},{"dsv":7,"sexagesimal":8}],7:[function(_dereq_,module,exports){
var fs = _dereq_("fs");
module.exports = new Function("dsv.version = \"0.0.3\";\n\ndsv.tsv = dsv(\"\\t\");\ndsv.csv = dsv(\",\");\n\nfunction dsv(delimiter) {\n var dsv = {},\n reFormat = new RegExp(\"[\\\"\" + delimiter + \"\\n]\"),\n delimiterCode = delimiter.charCodeAt(0);\n\n dsv.parse = function(text, f) {\n var o;\n return dsv.parseRows(text, function(row, i) {\n if (o) return o(row, i - 1);\n var a = new Function(\"d\", \"return {\" + row.map(function(name, i) {\n return JSON.stringify(name) + \": d[\" + i + \"]\";\n }).join(\",\") + \"}\");\n o = f ? function(row, i) { return f(a(row), i); } : a;\n });\n };\n\n dsv.parseRows = function(text, f) {\n var EOL = {}, // sentinel value for end-of-line\n EOF = {}, // sentinel value for end-of-file\n rows = [], // output rows\n N = text.length,\n I = 0, // current character index\n n = 0, // the current line number\n t, // the current token\n eol; // is the current token followed by EOL?\n\n function token() {\n if (I >= N) return EOF; // special case: end of file\n if (eol) return eol = false, EOL; // special case: end of line\n\n // special case: quotes\n var j = I;\n if (text.charCodeAt(j) === 34) {\n var i = j;\n while (i++ < N) {\n if (text.charCodeAt(i) === 34) {\n if (text.charCodeAt(i + 1) !== 34) break;\n ++i;\n }\n }\n I = i + 2;\n var c = text.charCodeAt(i + 1);\n if (c === 13) {\n eol = true;\n if (text.charCodeAt(i + 2) === 10) ++I;\n } else if (c === 10) {\n eol = true;\n }\n return text.substring(j + 1, i).replace(/\"\"/g, \"\\\"\");\n }\n\n // common case: find next delimiter or newline\n while (I < N) {\n var c = text.charCodeAt(I++), k = 1;\n if (c === 10) eol = true; // \\n\n else if (c === 13) { eol = true; if (text.charCodeAt(I) === 10) ++I, ++k; } // \\r|\\r\\n\n else if (c !== delimiterCode) continue;\n return text.substring(j, I - k);\n }\n\n // special case: last token before EOF\n return text.substring(j);\n }\n\n while ((t = token()) !== EOF) {\n var a = [];\n while (t !== EOL && t !== EOF) {\n a.push(t);\n t = token();\n }\n if (f && !(a = f(a, n++))) continue;\n rows.push(a);\n }\n\n return rows;\n };\n\n dsv.format = function(rows) {\n if (Array.isArray(rows[0])) return dsv.formatRows(rows); // deprecated; use formatRows\n var fieldSet = {}, fields = [];\n\n // Compute unique fields in order of discovery.\n rows.forEach(function(row) {\n for (var field in row) {\n if (!(field in fieldSet)) {\n fields.push(fieldSet[field] = field);\n }\n }\n });\n\n return [fields.map(formatValue).join(delimiter)].concat(rows.map(function(row) {\n return fields.map(function(field) {\n return formatValue(row[field]);\n }).join(delimiter);\n })).join(\"\\n\");\n };\n\n dsv.formatRows = function(rows) {\n return rows.map(formatRow).join(\"\\n\");\n };\n\n function formatRow(row) {\n return row.map(formatValue).join(delimiter);\n }\n\n function formatValue(text) {\n return reFormat.test(text) ? \"\\\"\" + text.replace(/\\\"/g, \"\\\"\\\"\") + \"\\\"\" : text;\n }\n\n return dsv;\n}\n" + ";return dsv")();
},{"fs":2}],8:[function(_dereq_,module,exports){
module.exports = function(x, dims) {
if (!dims) dims = 'NSEW';
if (typeof x !== 'string') return null;
var r = /^([0-9.]+)°? *(?:([0-9.]+)['] *)?(?:([0-9.]+)(?:''|"|”|″) *)?([NSEW])?/,
m = x.match(r);
if (!m) return null;
else if (m[4] && dims.indexOf(m[4]) === -1) return null;
else return (((m[1]) ? parseFloat(m[1]) : 0) +
((m[2] ? parseFloat(m[2]) / 60 : 0)) +
((m[3] ? parseFloat(m[3]) / 3600 : 0))) *
((m[4] && m[4] === 'S' || m[4] === 'W') ? -1 : 1);
};
},{}],9:[function(_dereq_,module,exports){
(function (process){toGeoJSON = (function() {
'use strict';
var removeSpace = (/\s*/g),
trimSpace = (/^\s*|\s*$/g),
splitSpace = (/\s+/);
// generate a short, numeric hash of a string
function okhash(x) {
if (!x || !x.length) return 0;
for (var i = 0, h = 0; i < x.length; i++) {
h = ((h << 5) - h) + x.charCodeAt(i) | 0;
} return h;
}
// all Y children of X
function get(x, y) { return x.getElementsByTagName(y); }
function attr(x, y) { return x.getAttribute(y); }
function attrf(x, y) { return parseFloat(attr(x, y)); }
// one Y child of X, if any, otherwise null
function get1(x, y) { var n = get(x, y); return n.length ? n[0] : null; }
// https://developer.mozilla.org/en-US/docs/Web/API/Node.normalize
function norm(el) { if (el.normalize) { el.normalize(); } return el; }
// cast array x into numbers
function numarray(x) {
for (var j = 0, o = []; j < x.length; j++) o[j] = parseFloat(x[j]);
return o;
}
function clean(x) {
var o = {};
for (var i in x) if (x[i]) o[i] = x[i];
return o;
}
// get the content of a text node, if any
function nodeVal(x) { if (x) {norm(x);} return x && x.firstChild && x.firstChild.nodeValue; }
// get one coordinate from a coordinate array, if any
function coord1(v) { return numarray(v.replace(removeSpace, '').split(',')); }
// get all coordinates from a coordinate array as [[],[]]
function coord(v) {
var coords = v.replace(trimSpace, '').split(splitSpace),
o = [];
for (var i = 0; i < coords.length; i++) {
o.push(coord1(coords[i]));
}
return o;
}
function coordPair(x) {
var ll = [attrf(x, 'lon'), attrf(x, 'lat')],
ele = get1(x, 'ele');
if (ele) ll.push(parseFloat(nodeVal(ele)));
return ll;
}
// create a new feature collection parent object
function fc() {
return {
type: 'FeatureCollection',
features: []
};
}
var serializer;
if (typeof XMLSerializer !== 'undefined') {
serializer = new XMLSerializer();
// only require xmldom in a node environment
} else if (typeof exports === 'object' && typeof process === 'object' && !process.browser) {
serializer = new (_dereq_('xmldom').XMLSerializer)();
}
function xml2str(str) { return serializer.serializeToString(str); }
var t = {
kml: function(doc, o) {
o = o || {};
var gj = fc(),
// styleindex keeps track of hashed styles in order to match features
styleIndex = {},
// atomic geospatial types supported by KML - MultiGeometry is
// handled separately
geotypes = ['Polygon', 'LineString', 'Point', 'Track'],
// all root placemarks in the file
placemarks = get(doc, 'Placemark'),
styles = get(doc, 'Style');
for (var k = 0; k < styles.length; k++) {
styleIndex['#' + attr(styles[k], 'id')] = okhash(xml2str(styles[k])).toString(16);
}
for (var j = 0; j < placemarks.length; j++) {
gj.features = gj.features.concat(getPlacemark(placemarks[j]));
}
function gxCoord(v) { return numarray(v.split(' ')); }
function gxCoords(root) {
var elems = get(root, 'coord', 'gx'), coords = [];
for (var i = 0; i < elems.length; i++) coords.push(gxCoord(nodeVal(elems[i])));
return coords;
}
function getGeometry(root) {
var geomNode, geomNodes, i, j, k, geoms = [];
if (get1(root, 'MultiGeometry')) return getGeometry(get1(root, 'MultiGeometry'));
if (get1(root, 'MultiTrack')) return getGeometry(get1(root, 'MultiTrack'));
for (i = 0; i < geotypes.length; i++) {
geomNodes = get(root, geotypes[i]);
if (geomNodes) {
for (j = 0; j < geomNodes.length; j++) {
geomNode = geomNodes[j];
if (geotypes[i] == 'Point') {
geoms.push({
type: 'Point',
coordinates: coord1(nodeVal(get1(geomNode, 'coordinates')))
});
} else if (geotypes[i] == 'LineString') {
geoms.push({
type: 'LineString',
coordinates: coord(nodeVal(get1(geomNode, 'coordinates')))
});
} else if (geotypes[i] == 'Polygon') {
var rings = get(geomNode, 'LinearRing'),
coords = [];
for (k = 0; k < rings.length; k++) {
coords.push(coord(nodeVal(get1(rings[k], 'coordinates'))));
}
geoms.push({
type: 'Polygon',
coordinates: coords
});
} else if (geotypes[i] == 'Track') {
geoms.push({
type: 'LineString',
coordinates: gxCoords(geomNode)
});
}
}
}
}
return geoms;
}
function getPlacemark(root) {
var geoms = getGeometry(root), i, properties = {},
name = nodeVal(get1(root, 'name')),
styleUrl = nodeVal(get1(root, 'styleUrl')),
description = nodeVal(get1(root, 'description')),
timeSpan = get1(root, 'TimeSpan'),
extendedData = get1(root, 'ExtendedData');
if (!geoms.length) return [];
if (name) properties.name = name;
if (styleUrl && styleIndex[styleUrl]) {
properties.styleUrl = styleUrl;
properties.styleHash = styleIndex[styleUrl];
}
if (description) properties.description = description;
if (timeSpan) {
var begin = nodeVal(get1(timeSpan, 'begin'));
var end = nodeVal(get1(timeSpan, 'end'));
properties.timespan = { begin: begin, end: end };
}
if (extendedData) {
var datas = get(extendedData, 'Data'),
simpleDatas = get(extendedData, 'SimpleData');
for (i = 0; i < datas.length; i++) {
properties[datas[i].getAttribute('name')] = nodeVal(get1(datas[i], 'value'));
}
for (i = 0; i < simpleDatas.length; i++) {
properties[simpleDatas[i].getAttribute('name')] = nodeVal(simpleDatas[i]);
}
}
return [{
type: 'Feature',
geometry: (geoms.length === 1) ? geoms[0] : {
type: 'GeometryCollection',
geometries: geoms
},
properties: properties
}];
}
return gj;
},
gpx: function(doc, o) {
var i,
tracks = get(doc, 'trk'),
routes = get(doc, 'rte'),
waypoints = get(doc, 'wpt'),
// a feature collection
gj = fc();
for (i = 0; i < tracks.length; i++) {
gj.features.push(getLinestring(tracks[i], 'trkpt'));
}
for (i = 0; i < routes.length; i++) {
gj.features.push(getLinestring(routes[i], 'rtept'));
}
for (i = 0; i < waypoints.length; i++) {
gj.features.push(getPoint(waypoints[i]));
}
function getLinestring(node, pointname) {
var j, pts = get(node, pointname), line = [];
for (j = 0; j < pts.length; j++) {
line.push(coordPair(pts[j]));
}
return {
type: 'Feature',
properties: getProperties(node),
geometry: {
type: 'LineString',
coordinates: line
}
};
}
function getPoint(node) {
var prop = getProperties(node);
prop.sym = nodeVal(get1(node, 'sym'));
return {
type: 'Feature',
properties: prop,
geometry: {
type: 'Point',
coordinates: coordPair(node)
}
};
}
function getProperties(node) {
var meta = ['name', 'desc', 'author', 'copyright', 'link',
'time', 'keywords'],
prop = {},
k;
for (k = 0; k < meta.length; k++) {
prop[meta[k]] = nodeVal(get1(node, meta[k]));
}
return clean(prop);
}
return gj;
}
};
return t;
})();
if (typeof module !== 'undefined') module.exports = toGeoJSON;
}).call(this,_dereq_("/Users/tmcw/src/leaflet-omnivore/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"))
},{"/Users/tmcw/src/leaflet-omnivore/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":4,"xmldom":3}],10:[function(_dereq_,module,exports){
var topojson = module.exports = _dereq_("./topojson");
topojson.topology = _dereq_("./lib/topojson/topology");
topojson.simplify = _dereq_("./lib/topojson/simplify");
topojson.clockwise = _dereq_("./lib/topojson/clockwise");
topojson.filter = _dereq_("./lib/topojson/filter");
topojson.prune = _dereq_("./lib/topojson/prune");
topojson.bind = _dereq_("./lib/topojson/bind");
},{"./lib/topojson/bind":11,"./lib/topojson/clockwise":14,"./lib/topojson/filter":18,"./lib/topojson/prune":21,"./lib/topojson/simplify":23,"./lib/topojson/topology":26,"./topojson":37}],11:[function(_dereq_,module,exports){
var type = _dereq_("./type"),
topojson = _dereq_("../../");
module.exports = function(topology, propertiesById) {
var bind = type({
geometry: function(geometry) {
var properties0 = geometry.properties,
properties1 = propertiesById[geometry.id];
if (properties1) {
if (properties0) for (var k in properties1) properties0[k] = properties1[k];
else for (var k in properties1) { geometry.properties = properties1; break; }
}
this.defaults.geometry.call(this, geometry);
},
LineString: noop,
MultiLineString: noop,
Point: noop,
MultiPoint: noop,
Polygon: noop,
MultiPolygon: noop
});
for (var key in topology.objects) {
bind.object(topology.objects[key]);
}
};
function noop() {}
},{"../../":10,"./type":36}],12:[function(_dereq_,module,exports){
// Computes the bounding box of the specified hash of GeoJSON objects.
module.exports = function(objects) {
var x0 = Infinity,
y0 = Infinity,
x1 = -Infinity,
y1 = -Infinity;
function boundGeometry(geometry) {
if (geometry && boundGeometryType.hasOwnProperty(geometry.type)) boundGeometryType[geometry.type](geometry);
}
var boundGeometryType = {
GeometryCollection: function(o) { o.geometries.forEach(boundGeometry); },
Point: function(o) { boundPoint(o.coordinates); },
MultiPoint: function(o) { o.coordinates.forEach(boundPoint); },
LineString: function(o) { boundLine(o.coordinates); },
MultiLineString: function(o) { o.coordinates.forEach(boundLine); },
Polygon: function(o) { o.coordinates.forEach(boundLine); },
MultiPolygon: function(o) { o.coordinates.forEach(boundMultiLine); }
};
function boundPoint(coordinates) {
var x = coordinates[0],
y = coordinates[1];
if (x < x0) x0 = x;
if (x > x1) x1 = x;
if (y < y0) y0 = y;
if (y > y1) y1 = y;
}
function boundLine(coordinates) {
coordinates.forEach(boundPoint);
}
function boundMultiLine(coordinates) {
coordinates.forEach(boundLine);
}
for (var key in objects) {
boundGeometry(objects[key]);
}
return [x0, y0, x1, y1];
};
},{}],13:[function(_dereq_,module,exports){
exports.name = "cartesian";
exports.formatDistance = formatDistance;
exports.ringArea = ringArea;
exports.absoluteArea = Math.abs;
exports.triangleArea = triangleArea;
exports.distance = distance;
function formatDistance(d) {
return d.toString();
}
function ringArea(ring) {
var i = 0,
n = ring.length,
area = ring[n - 1][1] * ring[0][0] - ring[n - 1][0] * ring[0][1];
while (++i < n) {
area += ring[i - 1][1] * ring[i][0] - ring[i - 1][0] * ring[i][1];
}
return -area * .5; // ensure clockwise pixel areas are positive
}
function triangleArea(triangle) {
return Math.abs(
(triangle[0][0] - triangle[2][0]) * (triangle[1][1] - triangle[0][1])
- (triangle[0][0] - triangle[1][0]) * (triangle[2][1] - triangle[0][1])
);
}
function distance(x0, y0, x1, y1) {
var dx = x0 - x1, dy = y0 - y1;
return Math.sqrt(dx * dx + dy * dy);
}
},{}],14:[function(_dereq_,module,exports){
var type = _dereq_("./type"),
systems = _dereq_("./coordinate-systems"),
topojson = _dereq_("../../");
module.exports = function(object, options) {
if (object.type === "Topology") clockwiseTopology(object, options);
else clockwiseGeometry(object, options);
};
function clockwiseGeometry(object, options) {
var system = null;
if (options)
"coordinate-system" in options && (system = systems[options["coordinate-system"]]);
var clockwisePolygon = clockwisePolygonSystem(system.ringArea, reverse);
type({
LineString: noop,
MultiLineString: noop,
Point: noop,
MultiPoint: noop,
Polygon: function(polygon) { clockwisePolygon(polygon.coordinates); },
MultiPolygon: function(multiPolygon) { multiPolygon.coordinates.forEach(clockwisePolygon); }
}).object(object);
function reverse(array) { array.reverse(); }
}
function clockwiseTopology(topology, options) {
var system = null;
if (options)
"coordinate-system" in options && (system = systems[options["coordinate-system"]]);
var clockwisePolygon = clockwisePolygonSystem(ringArea, reverse);
var clockwise = type({
LineString: noop,
MultiLineString: noop,
Point: noop,
MultiPoint: noop,
Polygon: function(polygon) { clockwisePolygon(polygon.arcs); },
MultiPolygon: function(multiPolygon) { multiPolygon.arcs.forEach(clockwisePolygon); }
});
for (var key in topology.objects) {
clockwise.object(topology.objects[key]);
}
function ringArea(ring) {
return system.ringArea(topojson.feature(topology, {type: "Polygon", arcs: [ring]}).geometry.coordinates[0]);
}
// TODO It might be slightly more compact to reverse the arc.
function reverse(ring) {
var i = -1, n = ring.length;
ring.reverse();
while (++i < n) ring[i] = ~ring[i];
}
};
function clockwisePolygonSystem(ringArea, reverse) {
return function(rings) {
if (!(n = rings.length)) return;
var n,
areas = new Array(n),
max = -Infinity,
best,
area,
t;
// Find the largest absolute ring area; this should be the exterior ring.
for (var i = 0; i < n; ++i) {
var area = Math.abs(areas[i] = ringArea(rings[i]));
if (area > max) max = area, best = i;
}
// Ensure the largest ring appears first.
if (best) {
t = rings[best], rings[best] = rings[0], rings[0] = t;
t = areas[best], areas[best] = areas[0], areas[0] = t;
}
if (areas[0] < 0) reverse(rings[0]);
for (var i = 1; i < n; ++i) {
if (areas[i] > 0) reverse(rings[i]);
}
};
}
function noop() {}
},{"../../":10,"./coordinate-systems":16,"./type":36}],15:[function(_dereq_,module,exports){
// Given a hash of GeoJSON objects and an id function, invokes the id function
// to compute a new id for each object that is a feature. The function is passed
// the feature and is expected to return the new feature id, or null if the
// feature should not have an id.
module.exports = function(objects, id) {
if (arguments.length < 2) id = function(d) { return d.id; };
function idObject(object) {
if (object && idObjectType.hasOwnProperty(object.type)) idObjectType[object.type](object);
}
function idFeature(feature) {
var i = id(feature);
if (i == null) delete feature.id;
else feature.id = i;
}
var idObjectType = {
Feature: idFeature,
FeatureCollection: function(collection) { collection.features.forEach(idFeature); }
};
for (var key in objects) {
idObject(objects[key]);
}
return objects;
};
},{}],16:[function(_dereq_,module,exports){
module.exports = {
cartesian: _dereq_("./cartesian"),
spherical: _dereq_("./spherical")
};
},{"./cartesian":13,"./spherical":24}],17:[function(_dereq_,module,exports){
// Given a TopoJSON topology in absolute (quantized) coordinates,
// converts to fixed-point delta encoding.
// This is a destructive operation that modifies the given topology!
module.exports = function(topology) {
var arcs = topology.arcs,
i = -1,
n = arcs.length;
while (++i < n) {
var arc = arcs[i],
j = 0,
m = arc.length,
point = arc[0],
x0 = point[0],
y0 = point[1],
x1,
y1;
while (++j < m) {
point = arc[j];
x1 = point[0];
y1 = point[1];
arc[j] = [x1 - x0, y1 - y0];
x0 = x1;
y0 = y1;
}
}
return topology;
};
},{}],18:[function(_dereq_,module,exports){
var type = _dereq_("./type"),
prune = _dereq_("./prune"),
clockwise = _dereq_("./clockwise"),
systems = _dereq_("./coordinate-systems"),
topojson = _dereq_("../../");
module.exports = function(topology, options) {
var system = null,
forceClockwise = true, // force exterior rings to be clockwise?
minimumArea;
if (options)
"coordinate-system" in options && (system = systems[options["coordinate-system"]]),
"minimum-area" in options && (minimumArea = +options["minimum-area"]),
"force-clockwise" in options && (forceClockwise = !!options["force-clockwise"]);
if (forceClockwise) clockwise(topology, options); // deprecated; for backwards-compatibility
if (!(minimumArea > 0)) minimumArea = Number.MIN_VALUE;
var filter = type({
LineString: noop, // TODO remove empty lines
MultiLineString: noop,
Point: noop,
MultiPoint: noop,
Polygon: function(polygon) {
polygon.arcs = polygon.arcs.filter(ringArea);
if (!polygon.arcs.length) {
polygon.type = null;
delete polygon.arcs;
}
},
MultiPolygon: function(multiPolygon) {
multiPolygon.arcs = multiPolygon.arcs.map(function(polygon) {
return polygon.filter(ringArea);
}).filter(function(polygon) {
return polygon.length;
});
if (!multiPolygon.arcs.length) {
multiPolygon.type = null;
delete multiPolygon.arcs;
}
},
GeometryCollection: function(collection) {
this.defaults.GeometryCollection.call(this, collection);
collection.geometries = collection.geometries.filter(function(geometry) { return geometry.type != null; });
if (!collection.geometries.length) {
collection.type = null;
delete collection.geometries;
}
}
});
for (var key in topology.objects) {
filter.object(topology.objects[key]);
}
prune(topology, options);
function ringArea(ring) {
var topopolygon = {type: "Polygon", arcs: [ring]},
geopolygon = topojson.feature(topology, topopolygon),
exterior = geopolygon.geometry.coordinates[0],
exteriorArea = system.absoluteArea(system.ringArea(exterior));
return exteriorArea >= minimumArea;
}
};
function noop() {}
},{"../../":10,"./clockwise":14,"./coordinate-systems":16,"./prune":21,"./type":36}],19:[function(_dereq_,module,exports){
// Given a hash of GeoJSON objects, replaces Features with geometry objects.
// This is a destructive operation that modifies the input objects!
module.exports = function(objects) {
function geomifyObject(object) {
return (object && geomifyObjectType.hasOwnProperty(object.type)
? geomifyObjectType[object.type]
: geomifyGeometry)(object);
}
function geomifyFeature(feature) {
var geometry = feature.geometry;
if (geometry == null) {
feature.type = null;
} else {
geomifyGeometry(geometry);
feature.type = geometry.type;
if (geometry.geometries) feature.geometries = geometry.geometries;
else if (geometry.coordinates) feature.coordinates = geometry.coordinates;
}
delete feature.geometry;
return feature;
}
function geomifyGeometry(geometry) {
if (!geometry) return {type: null};
if (geomifyGeometryType.hasOwnProperty(geometry.type)) geomifyGeometryType[geometry.type](geometry);
return geometry;
}
var geomifyObjectType = {
Feature: geomifyFeature,
FeatureCollection: function(collection) {
collection.type = "GeometryCollection";
collection.geometries = collection.features;
collection.features.forEach(geomifyFeature);
delete collection.features;
return collection;
}
};
var geomifyGeometryType = {
GeometryCollection: function(o) {
var geometries = o.geometries, i = -1, n = geometries.length;
while (++i < n) geometries[i] = geomifyGeometry(geometries[i]);
},
MultiPoint: function(o) {
if (!o.coordinates.length) {
o.type = null;
delete o.coordinates;
} else if (o.coordinates.length < 2) {
o.type = "Point";
o.coordinates = o.coordinates[0];
}
},
LineString: function(o) {
if (!o.coordinates.length) {
o.type = null;
delete o.coordinates;
}
},
MultiLineString: function(o) {
for (var lines = o.coordinates, i = 0, N = 0, n = lines.length; i < n; ++i) {
var line = lines[i];
if (line.length) lines[N++] = line;
}
if (!N) {
o.type = null;
delete o.coordinates;
} else if (N < 2) {
o.type = "LineString";
o.coordinates = lines[0];
} else {
o.coordinates.length = N;
}
},
Polygon: function(o) {
for (var rings = o.coordinates, i = 0, N = 0, n = rings.length; i < n; ++i) {
var ring = rings[i];
if (ring.length) rings[N++] = ring;
}
if (!N) {
o.type = null;
delete o.coordinates;
} else {
o.coordinates.length = N;
}
},
MultiPolygon: function(o) {
for (var polygons = o.coordinates, j = 0, M = 0, m = polygons.length; j < m; ++j) {
for (var rings = polygons[j], i = 0, N = 0, n = rings.length; i < n; ++i) {
var ring = rings[i];
if (ring.length) rings[N++] = ring;
}
if (N) {
rings.length = N;
polygons[M++] = rings;
}
}
if (!M) {
o.type = null;
delete o.coordinates;
} else if (M < 2) {
o.type = "Polygon";
o.coordinates = polygons[0];
} else {
polygons.length = M;
}
}
};
for (var key in objects) {
objects[key] = geomifyObject(objects[key]);
}
return objects;
};
},{}],20:[function(_dereq_,module,exports){
module.exports = function(objects, filter) {
function prefilterGeometry(geometry) {
if (!geometry) return {type: null};
if (prefilterGeometryType.hasOwnProperty(geometry.type)) prefilterGeometryType[geometry.type](geometry);
return geometry;
}
var prefilterGeometryType = {
GeometryCollection: function(o) {
var geometries = o.geometries, i = -1, n = geometries.length;
while (++i < n) geometries[i] = prefilterGeometry(geometries[i]);
},
Polygon: function(o) {
for (var rings = o.coordinates, i = 0, N = 0, n = rings.length; i < n; ++i) {
var ring = rings[i];
if (filter(ring)) rings[N++] = ring;
}
if (!N) {
o.type = null;
delete o.coordinates;
} else {
o.coordinates.length = N;
}
},
MultiPolygon: function(o) {
for (var polygons = o.coordinates, j = 0, M = 0, m = polygons.length; j < m; ++j) {
for (var rings = polygons[j], i = 0, N = 0, n = rings.length; i < n; ++i) {
var ring = rings[i];
if (filter(ring)) rings[N++] = ring;
}
if (N) {
rings.length = N;
polygons[M++] = rings;
}
}
if (!M) {
o.type = null;
delete o.coordinates;
} else if (M < 2) {
o.type = "Polygon";
o.coordinates = polygons[0];
} else {
polygons.length = M;
}
}
};
for (var key in objects) {
objects[key] = prefilterGeometry(objects[key]);
}
return objects;
};
},{}],21:[function(_dereq_,module,exports){
module.exports = function(topology, options) {
var verbose = false,
objects = topology.objects,
oldArcs = topology.arcs,
oldArcCount = oldArcs.length,
newArcs = topology.arcs = [],
newArcCount = 0,
newIndexByOldIndex = new Array(oldArcs.length);
if (options)
"verbose" in options && (verbose = !!options["verbose"]);
function pruneGeometry(geometry) {
if (geometry && pruneGeometryType.hasOwnProperty(geometry.type)) pruneGeometryType[geometry.type](geometry);
}
var pruneGeometryType = {
GeometryCollection: function(o) { o.geometries.forEach(pruneGeometry); },
LineString: function(o) { pruneArcs(o.arcs); },
MultiLineString: function(o) { o.arcs.forEach(pruneArcs); },
Polygon: function(o) { o.arcs.forEach(pruneArcs); },
MultiPolygon: function(o) { o.arcs.forEach(pruneMultiArcs); }
};
function pruneArcs(arcs) {
for (var i = 0, m = 0, n = arcs.length; i < n; ++i) {
var oldIndex = arcs[i],
oldReverse = oldIndex < 0 && (oldIndex = ~oldIndex, true),
oldArc = oldArcs[oldIndex],
newIndex;
// Skip collapsed arc segments.
if (oldArc.length < 3 && !oldArc[1][0] && !oldArc[1][1]) continue;
// If this is the first instance of this arc,
// record it under its new index.
if ((newIndex = newIndexByOldIndex[oldIndex]) == null) {
newIndexByOldIndex[oldIndex] = newIndex = newArcCount++;
newArcs[newIndex] = oldArcs[oldIndex];
}
arcs[m++] = oldReverse ? ~newIndex : newIndex;
}
// If all were collapsed, restore the last arc to avoid collapsing the line.
if (!(arcs.length = m) && n) {
// If this is the first instance of this arc,
// record it under its new index.
if ((newIndex = newIndexByOldIndex[oldIndex]) == null) {
newIndexByOldIndex[oldIndex] = newIndex = newArcCount++;
newArcs[newIndex] = oldArcs[oldIndex];
}
arcs[0] = oldReverse ? ~newIndex : newIndex;
}
}
function pruneMultiArcs(arcs) {
arcs.forEach(pruneArcs);
}
for (var key in objects) {
pruneGeometry(objects[key]);
}
if (verbose) console.warn("prune: retained " + newArcCount + " / " + oldArcCount + " arcs (" + Math.round(newArcCount / oldArcCount * 100) + "%)");
return topology;
};
function noop() {}
},{}],22:[function(_dereq_,module,exports){
module.exports = function(objects, bbox, Q) {
var x0 = isFinite(bbox[0]) ? bbox[0] : 0,
y0 = isFinite(bbox[1]) ? bbox[1] : 0,
x1 = isFinite(bbox[2]) ? bbox[2] : 0,
y1 = isFinite(bbox[3]) ? bbox[3] : 0,
kx = x1 - x0 ? (Q - 1) / (x1 - x0) : 1,
ky = y1 - y0 ? (Q - 1) / (y1 - y0) : 1;
function quantizeGeometry(geometry) {
if (geometry && quantizeGeometryType.hasOwnProperty(geometry.type)) quantizeGeometryType[geometry.type](geometry);
}
var quantizeGeometryType = {
GeometryCollection: function(o) { o.geometries.forEach(quantizeGeometry); },
Point: function(o) { quantizePoint(o.coordinates); },
MultiPoint: function(o) { o.coordinates.forEach(quantizePoint); },
LineString: function(o) {
var line = o.coordinates;
quantizeLine(line);
if (line.length < 2) line[1] = line[0]; // must have 2+
},
MultiLineString: function(o) {
for (var lines = o.coordinates, i = 0, n = lines.length; i < n; ++i) {
var line = lines[i];
quantizeLine(line);
if (line.length < 2) line[1] = line[0]; // must have 2+
}
},
Polygon: function(o) {
for (var rings = o.coordinates, i = 0, n = rings.length; i < n; ++i) {
var ring = rings[i];
quantizeLine(ring);
while (ring.length < 4) ring.push(ring[0]); // must have 4+
}
},
MultiPolygon: function(o) {
for (var polygons = o.coordinates, i = 0, n = polygons.length; i < n; ++i) {
for (var rings = polygons[i], j = 0, m = rings.length; j < m; ++j) {
var ring = rings[j];
quantizeLine(ring);
while (ring.length < 4) ring.push(ring[0]); // must have 4+
}
}
}
};
function quantizePoint(coordinates) {
coordinates[0] = Math.round((coordinates[0] - x0) * kx);
coordinates[1] = Math.round((coordinates[1] - y0) * ky);
}
function quantizeLine(coordinates) {
var i = 0,
j = 1,
n = coordinates.length,
pi = coordinates[0],
pj,
px = pi[0] = Math.round((pi[0] - x0) * kx),
py = pi[1] = Math.round((pi[1] - y0) * ky),
x,
y;
while (++i < n) {
pi = coordinates[i];
x = Math.round((pi[0] - x0) * kx);
y = Math.round((pi[1] - y0) * ky);
if (x !== px || y !== py) { // skip coincident points
pj = coordinates[j++];
pj[0] = px = x;
pj[1] = py = y;
}
}
coordinates.length = j;
}
for (var key in objects) {
quantizeGeometry(objects[key]);
}
return {
scale: [1 / kx, 1 / ky],
translate: [x0, y0]
};
};
},{}],23:[function(_dereq_,module,exports){
var topojson = _dereq_("../../"),
systems = _dereq_("./coordinate-systems");
module.exports = function(topology, options) {
var minimumArea = 0,
retainProportion,
verbose = false,
system = null,
N = topology.arcs.reduce(function(p, v) { return p + v.length; }, 0),
M = 0;
if (options)
"minimum-area" in options && (minimumArea = +options["minimum-area"]),
"coordinate-system" in options && (system = systems[options["coordinate-system"]]),
"retain-proportion" in options && (retainProportion = +options["retain-proportion"]),
"verbose" in options && (verbose = !!options["verbose"]);
topojson.presimplify(topology, system.triangleArea);
if (retainProportion) {
var areas = [];
topology.arcs.forEach(function(arc) {
arc.forEach(function(point) {
areas.push(point[2]);
});
});
options["minimum-area"] = minimumArea = N ? areas.sort(function(a, b) { return b - a; })[Math.ceil((N - 1) * retainProportion)] : 0;
if (verbose) console.warn("simplification: effective minimum area " + minimumArea.toPrecision(3));
}
topology.arcs.forEach(topology.transform ? function(arc) {
var dx = 0,
dy = 0, // accumulate removed points
i = -1,
j = -1,
n = arc.length,
source,
target;
while (++i < n) {
source = arc[i];
if (source[2] >= minimumArea) {
target = arc[++j];
target[0] = source[0] + dx;
target[1] = source[1] + dy;
dx = dy = 0;
} else {
dx += source[0];
dy += source[1];
}
}
arc.length = ++j;
} : function(arc) {
var i = -1,
j = -1,
n = arc.length,
point;
while (++i < n) {
point = arc[i];
if (point[2] >= minimumArea) {
arc[++j] = point;
}
}
arc.length = ++j;
});
// Remove computed area (z) for each point.
// This is done as a separate pass because some coordinates may be shared
// between arcs (such as the last point and first point of a cut line).
topology.arcs.forEach(function(arc) {
var i = -1, n = arc.length;
while (++i < n) arc[i].length = 2;
M += arc.length;
});
if (verbose) console.warn("simplification: retained " + M + " / " + N + " points (" + Math.round((M / N) * 100) + "%)");
return topology;
};
},{"../../":10,"./coordinate-systems":16}],24:[function(_dereq_,module,exports){
var π = Math.PI,
π_4 = π / 4,
radians = π / 180;
exports.name = "spherical";
exports.formatDistance = formatDistance;
exports.ringArea = ringArea;
exports.absoluteArea = absoluteArea;
exports.triangleArea = triangleArea;
exports.distance = haversinDistance; // why two implementations?
function formatDistance(radians) {
var km = radians * 6371;
return (km > 1 ? km.toFixed(3) + "km" : (km * 1000).toPrecision(3) + "m")
+ " (" + (radians * 180 / Math.PI).toPrecision(3) + "°)";
}
function ringArea(ring) {
if (!ring.length) return 0;
var area = 0,
p = ring[0],
λ = p[0] * radians,
φ = p[1] * radians / 2 + π_4,
λ0 = λ,
cosφ0 = Math.cos(φ),
sinφ0 = Math.sin(φ);
for (var i = 1, n = ring.length; i < n; ++i) {
p = ring[i], λ = p[0] * radians, φ = p[1] * radians / 2 + π_4;
// Spherical excess E for a spherical triangle with vertices: south pole,
// previous point, current point. Uses a formula derived from Cagnolis
// theorem. See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
var = λ - λ0,
cosφ = Math.cos(φ),
sinφ = Math.sin(φ),
k = sinφ0 * sinφ,
u = cosφ0 * cosφ + k * Math.cos(),
v = k * Math.sin();
area += Math.atan2(v, u);
// Advance the previous point.
λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ;
}
return 2 * (area > π ? area - 2 * π : area < -π ? area + 2 * π : area);
}
function absoluteArea(a) {
return a < 0 ? a + 4 * π : a;
}
function triangleArea(t) {
var a = distance(t[0], t[1]),
b = distance(t[1], t[2]),
c = distance(t[2], t[0]),
s = (a + b + c) / 2;
return 4 * Math.atan(Math.sqrt(Math.max(0, Math.tan(s / 2) * Math.tan((s - a) / 2) * Math.tan((s - b) / 2) * Math.tan((s - c) / 2))));
}
function distance(a, b) {
var Δλ = (b[0] - a[0]) * radians,
sinΔλ = Math.sin(Δλ),
cosΔλ = Math.cos(Δλ),
sinφ0 = Math.sin(a[1] * radians),
cosφ0 = Math.cos(a[1] * radians),
sinφ1 = Math.sin(b[1] * radians),
cosφ1 = Math.cos(b[1] * radians),
_;
return Math.atan2(Math.sqrt((_ = cosφ1 * sinΔλ) * _ + (_ = cosφ0 * sinφ1 - sinφ0 * cosφ1 * cosΔλ) * _), sinφ0 * sinφ1 + cosφ0 * cosφ1 * cosΔλ);
}
function haversinDistance(x0, y0, x1, y1) {
x0 *= radians, y0 *= radians, x1 *= radians, y1 *= radians;
return 2 * Math.asin(Math.sqrt(haversin(y1 - y0) + Math.cos(y0) * Math.cos(y1) * haversin(x1 - x0)));
}
function haversin(x) {
return (x = Math.sin(x / 2)) * x;
}
},{}],25:[function(_dereq_,module,exports){
var type = _dereq_("./type");
module.exports = function(objects, transform) {
var ε = 1e-2,
x0 = -180, x0e = x0 + ε,
x1 = 180, x1e = x1 - ε,
y0 = -90, y0e = y0 + ε,
y1 = 90, y1e = y1 - ε,
fragments = [];
if (transform) {
var kx = transform.scale[0],
ky = transform.scale[1],
dx = transform.translate[0],
dy = transform.translate[1];
x0 = Math.round((x0 - dx) / kx);
x1 = Math.round((x1 - dx) / kx);
y0 = Math.round((y0 - dy) / ky);
y1 = Math.round((y1 - dy) / ky);
x0e = Math.round((x0e - dx) / kx);
x1e = Math.round((x1e - dx) / kx);
y0e = Math.round((y0e - dy) / ky);
y1e = Math.round((y1e - dy) / ky);
}
function normalizePoint(y) {
return y <= y0e ? [0, y0] // south pole
: y >= y1e ? [0, y1] // north pole
: [x0, y]; // antimeridian
}
var stitch = type({
polygon: function(polygon) {
var rings = [];
// For each ring, detect where it crosses the antimeridian or pole.
for (var j = 0, m = polygon.length; j < m; ++j) {
var ring = polygon[j],
fragments = [];
// By default, assume that this ring doesnt need any stitching.
fragments.push(ring);
for (var i = 0, n = ring.length; i < n; ++i) {
var point = ring[i],
x = point[0],
y = point[1];
// If this is an antimeridian or polar point…
if (x <= x0e || x >= x1e || y <= y0e || y >= y1e) {
// Advance through any antimeridian or polar points…
for (var k = i + 1; k < n; ++k) {
var pointk = ring[k],
xk = pointk[0],
yk = pointk[1];
if (xk > x0e && xk < x1e && yk > y0e && yk < y1e) break;
}
// If this was just a single antimeridian or polar point,
// we dont need to cut this ring into a fragment;
// we can just leave it as-is.
if (k === i + 1) continue;
// Otherwise, if this is not the first point in the ring,
// cut the current fragment so that it ends at the current point.
// The current point is also normalized for later joining.
if (i) {
var fragmentBefore = ring.slice(0, i + 1);
fragmentBefore[fragmentBefore.length - 1] = normalizePoint(y);
fragments[fragments.length - 1] = fragmentBefore;
}
// If the ring started with an antimeridian fragment,
// we can ignore that fragment entirely.
else {
fragments.pop();
}
// If the remainder of the ring is an antimeridian fragment,
// move on to the next ring.
if (k >= n) break;
// Otherwise, add the remaining ring fragment and continue.
fragments.push(ring = ring.slice(k - 1));
ring[0] = normalizePoint(ring[0][1]);
i = -1;
n = ring.length;
}
}
// Now stitch the fragments back together into rings.
// To connect the fragments start-to-end, create a simple index by end.
var fragmentByStart = {},
fragmentByEnd = {};
// For each fragment…
for (var i = 0, n = fragments.length; i < n; ++i) {
var fragment = fragments[i],
start = fragment[0],
end = fragment[fragment.length - 1];
// If this fragment is closed, add it as a standalone ring.
if (start[0] === end[0] && start[1] === end[1]) {
rings.push(fragment);
fragments[i] = null;
continue;
}
fragment.index = i;
fragmentByStart[start] = fragmentByEnd[end] = fragment;
}
// For each open fragment…
for (var i = 0; i < n; ++i) {
var fragment = fragments[i];
if (fragment) {
var start = fragment[0],
end = fragment[fragment.length - 1],
startFragment = fragmentByEnd[start],
endFragment = fragmentByStart[end];
delete fragmentByStart[start];
delete fragmentByEnd[end];
// If this fragment is closed, add it as a standalone ring.
if (start[0] === end[0] && start[1] === end[1]) {
rings.push(fragment);
continue;
}
if (startFragment) {
delete fragmentByEnd[start];
delete fragmentByStart[startFragment[0]];
startFragment.pop(); // drop the shared coordinate
fragments[startFragment.index] = null;
fragment = startFragment.concat(fragment);
if (startFragment === endFragment) {
// Connect both ends to this single fragment to create a ring.
rings.push(fragment);
} else {
fragment.index = n++;
fragments.push(fragmentByStart[fragment[0]] = fragmentByEnd[fragment[fragment.length - 1]] = fragment);
}
} else if (endFragment) {
delete fragmentByStart[end];
delete fragmentByEnd[endFragment[endFragment.length - 1]];
fragment.pop(); // drop the shared coordinate
fragment = fragment.concat(endFragment);
fragment.index = n++;
fragments[endFragment.index] = null;
fragments.push(fragmentByStart[fragment[0]] = fragmentByEnd[fragment[fragment.length - 1]] = fragment);
} else {
fragment.push(fragment[0]); // close ring
rings.push(fragment);
}
}
}
}
// Copy the rings into the target polygon.
for (var i = 0, n = polygon.length = rings.length; i < n; ++i) {
polygon[i] = rings[i];
}
}
});
for (var key in objects) {
stitch.object(objects[key]);
}
};
},{"./type":36}],26:[function(_dereq_,module,exports){
var type = _dereq_("./type"),
stitch = _dereq_("./stitch"),
systems = _dereq_("./coordinate-systems"),
topologize = _dereq_("./topology/index"),
delta = _dereq_("./delta"),
geomify = _dereq_("./geomify"),
prefilter = _dereq_("./prefilter"),
quantize = _dereq_("./quantize"),
bounds = _dereq_("./bounds"),
computeId = _dereq_("./compute-id"),
transformProperties = _dereq_("./transform-properties");
var ε = 1e-6;
module.exports = function(objects, options) {
var Q = 1e4, // precision of quantization
id = function(d) { return d.id; }, // function to compute object id
propertyTransform = function() {}, // function to transform properties
transform,
minimumArea = 0,
stitchPoles = true,
verbose = false,
system = null;
if (options)
"verbose" in options && (verbose = !!options["verbose"]),
"stitch-poles" in options && (stitchPoles = !!options["stitch-poles"]),
"coordinate-system" in options && (system = systems[options["coordinate-system"]]),
"minimum-area" in options && (minimumArea = +options["minimum-area"]),
"quantization" in options && (Q = +options["quantization"]),
"id" in options && (id = options["id"]),
"property-transform" in options && (propertyTransform = options["property-transform"]);
// Compute the new feature id and transform properties.
computeId(objects, id);
transformProperties(objects, propertyTransform);
// Convert to geometry objects.
geomify(objects);
// Compute initial bounding box.
var bbox = bounds(objects);
// For automatic coordinate system determination, consider the bounding box.
var oversize = bbox[0] < -180 - ε
|| bbox[1] < -90 - ε
|| bbox[2] > 180 + ε
|| bbox[3] > 90 + ε;
if (!system) {
system = systems[oversize ? "cartesian" : "spherical"];
if (options) options["coordinate-system"] = system.name;
}
if (system === systems.spherical) {
if (oversize) throw new Error("spherical coordinates outside of [±180°, ±90°]");
// When near the spherical coordinate limits, clamp to nice round values.
// This avoids quantized coordinates that are slightly outside the limits.
if (bbox[0] < -180 + ε) bbox[0] = -180;
if (bbox[1] < -90 + ε) bbox[1] = -90;
if (bbox[2] > 180 - ε) bbox[2] = 180;
if (bbox[3] > 90 - ε) bbox[3] = 90;
}
if (verbose) {
console.warn("bounds: " + bbox.join(" ") + " (" + system.name + ")");
}
// Filter rings smaller than the minimum area.
// This can produce a simpler topology.
if (minimumArea) prefilter(objects, function(ring) {
return system.absoluteArea(system.ringArea(ring)) >= minimumArea;
});
// Compute the quantization transform.
if (Q) {
transform = quantize(objects, bbox, Q);
if (verbose) {
console.warn("quantization: " + transform.scale.map(function(degrees) { return system.formatDistance(degrees / 180 * Math.PI); }).join(" "));
}
}
// Remove any antimeridian cuts and restitch.
if (system === systems.spherical && stitchPoles) {
stitch(objects, transform);
}
// Compute the topology.
var topology = topologize(objects);
topology.bbox = bbox;
if (verbose) {
console.warn("topology: " + topology.arcs.length + " arcs, " + topology.arcs.reduce(function(p, v) { return p + v.length; }, 0) + " points");
}
// Convert to delta-encoding.
if (Q) topology.transform = transform, delta(topology);
return topology;
};
},{"./bounds":12,"./compute-id":15,"./coordinate-systems":16,"./delta":17,"./geomify":19,"./prefilter":20,"./quantize":22,"./stitch":25,"./topology/index":31,"./transform-properties":35,"./type":36}],27:[function(_dereq_,module,exports){
var join = _dereq_("./join");
// Given an extracted (pre-)topology, cuts (or rotates) arcs so that all shared
// point sequences are identified. The topology can then be subsequently deduped
// to remove exact duplicate arcs.
module.exports = function(topology) {
var junctionByPoint = join(topology),
coordinates = topology.coordinates,
lines = topology.lines,
rings = topology.rings;
for (var i = 0, n = lines.length; i < n; ++i) {
var line = lines[i],
lineMid = line[0],
lineEnd = line[1];
while (++lineMid < lineEnd) {
if (junctionByPoint.get(coordinates[lineMid])) {
var next = {0: lineMid, 1: line[1]};
line[1] = lineMid;
line = line.next = next;
}
}
}
for (var i = 0, n = rings.length; i < n; ++i) {
var ring = rings[i],
ringStart = ring[0],
ringMid = ringStart,
ringEnd = ring[1],
ringFixed = junctionByPoint.get(coordinates[ringStart]);
while (++ringMid < ringEnd) {
if (junctionByPoint.get(coordinates[ringMid])) {
if (ringFixed) {
var next = {0: ringMid, 1: ring[1]};
ring[1] = ringMid;
ring = ring.next = next;
} else { // For the first junction, we can rotate rather than cut.
rotateArray(coordinates, ringStart, ringEnd, ringEnd - ringMid);
coordinates[ringEnd] = coordinates[ringStart];
ringFixed = true;
ringMid = ringStart; // restart; we may have skipped junctions
}
}
}
}
return topology;
};
function rotateArray(array, start, end, offset) {
reverse(array, start, end);
reverse(array, start, start + offset);
reverse(array, start + offset, end);
}
function reverse(array, start, end) {
for (var mid = start + ((end-- - start) >> 1), t; start < mid; ++start, --end) {
t = array[start], array[start] = array[end], array[end] = t;
}
}
},{"./join":32}],28:[function(_dereq_,module,exports){
var join = _dereq_("./join"),
hashtable = _dereq_("./hashtable"),
hashPoint = _dereq_("./point-hash"),
equalPoint = _dereq_("./point-equal");
// Given a cut topology, combines duplicate arcs.
module.exports = function(topology) {
var coordinates = topology.coordinates,
lines = topology.lines,
rings = topology.rings,
arcCount = lines.length + rings.length;
delete topology.lines;
delete topology.rings;
// Count the number of (non-unique) arcs to initialize the hashtable safely.
for (var i = 0, n = lines.length; i < n; ++i) {
var line = lines[i]; while (line = line.next) ++arcCount;
}
for (var i = 0, n = rings.length; i < n; ++i) {
var ring = rings[i]; while (ring = ring.next) ++arcCount;
}
var arcsByEnd = hashtable(arcCount * 2, hashPoint, equalPoint),
arcs = topology.arcs = [];
for (var i = 0, n = lines.length; i < n; ++i) {
var line = lines[i];
do {
dedupLine(line);
} while (line = line.next);
}
for (var i = 0, n = rings.length; i < n; ++i) {
var ring = rings[i];
if (ring.next) { // arc is no longer closed
do {
dedupLine(ring);
} while (ring = ring.next);
} else {
dedupRing(ring);
}
}
function dedupLine(arc) {
var startPoint,
endPoint,
startArcs,
endArcs;
// Does this arc match an existing arc in order?
if (startArcs = arcsByEnd.get(startPoint = coordinates[arc[0]])) {
for (var i = 0, n = startArcs.length; i < n; ++i) {
var startArc = startArcs[i];
if (equalLine(startArc, arc)) {
arc[0] = startArc[0];
arc[1] = startArc[1];
return;
}
}
}
// Does this arc match an existing arc in reverse order?
if (endArcs = arcsByEnd.get(endPoint = coordinates[arc[1]])) {
for (var i = 0, n = endArcs.length; i < n; ++i) {
var endArc = endArcs[i];
if (reverseEqualLine(endArc, arc)) {
arc[1] = endArc[0];
arc[0] = endArc[1];
return;
}
}
}
if (startArcs) startArcs.push(arc); else arcsByEnd.set(startPoint, [arc]);
if (endArcs) endArcs.push(arc); else arcsByEnd.set(endPoint, [arc]);
arcs.push(arc);
}
function dedupRing(arc) {
var endPoint,
endArcs;
// Does this arc match an existing line in order, or reverse order?
// Rings are closed, so their start point and end point is the same.
if (endArcs = arcsByEnd.get(endPoint = coordinates[arc[0]])) {
for (var i = 0, n = endArcs.length; i < n; ++i) {
var endArc = endArcs[i];
if (equalRing(endArc, arc)) {
arc[0] = endArc[0];
arc[1] = endArc[1];
return;
}
if (reverseEqualRing(endArc, arc)) {
arc[0] = endArc[1];
arc[1] = endArc[0];
return;
}
}
}
// Otherwise, does this arc match an existing ring in order, or reverse order?
if (endArcs = arcsByEnd.get(endPoint = coordinates[arc[0] + findMinimumOffset(arc)])) {
for (var i = 0, n = endArcs.length; i < n; ++i) {
var endArc = endArcs[i];
if (equalRing(endArc, arc)) {
arc[0] = endArc[0];
arc[1] = endArc[1];
return;
}
if (reverseEqualRing(endArc, arc)) {
arc[0] = endArc[1];
arc[1] = endArc[0];
return;
}
}
}
if (endArcs) endArcs.push(arc); else arcsByEnd.set(endPoint, [arc]);
arcs.push(arc);
}
function equalLine(arcA, arcB) {
var ia = arcA[0], ib = arcB[0],
ja = arcA[1], jb = arcB[1];
if (ia - ja !== ib - jb) return false;
for (; ia <= ja; ++ia, ++ib) if (!equalPoint(coordinates[ia], coordinates[ib])) return false;
return true;
}
function reverseEqualLine(arcA, arcB) {
var ia = arcA[0], ib = arcB[0],
ja = arcA[1], jb = arcB[1];
if (ia - ja !== ib - jb) return false;
for (; ia <= ja; ++ia, --jb) if (!equalPoint(coordinates[ia], coordinates[jb])) return false;
return true;
}
function equalRing(arcA, arcB) {
var ia = arcA[0], ib = arcB[0],
ja = arcA[1], jb = arcB[1],
n = ja - ia;
if (n !== jb - ib) return false;
var ka = findMinimumOffset(arcA),
kb = findMinimumOffset(arcB);
for (var i = 0; i < n; ++i) {
if (!equalPoint(coordinates[ia + (i + ka) % n], coordinates[ib + (i + kb) % n])) return false;
}
return true;
}
function reverseEqualRing(arcA, arcB) {
var ia = arcA[0], ib = arcB[0],
ja = arcA[1], jb = arcB[1],
n = ja - ia;
if (n !== jb - ib) return false;
var ka = findMinimumOffset(arcA),
kb = n - findMinimumOffset(arcB);
for (var i = 0; i < n; ++i) {
if (!equalPoint(coordinates[ia + (i + ka) % n], coordinates[jb - (i + kb) % n])) return false;
}
return true;
}
// Rings are rotated to a consistent, but arbitrary, start point.
// This is necessary to detect when a ring and a rotated copy are dupes.
function findMinimumOffset(arc) {
var start = arc[0],
end = arc[1],
mid = start,
minimum = mid,
minimumPoint = coordinates[mid];
while (++mid < end) {
var point = coordinates[mid];
if (point[0] < minimumPoint[0] || point[0] === minimumPoint[0] && point[1] < minimumPoint[1]) {
minimum = mid;
minimumPoint = point;
}
}
return minimum - start;
}
return topology;
};
},{"./hashtable":30,"./join":32,"./point-equal":33,"./point-hash":34}],29:[function(_dereq_,module,exports){
// Extracts the lines and rings from the specified hash of geometry objects.
//
// Returns an object with three properties:
//
// * coordinates - shared buffer of [x, y] coordinates
// * lines - lines extracted from the hash, of the form [start, end]
// * rings - rings extracted from the hash, of the form [start, end]
//
// For each ring or line, start and end represent inclusive indexes into the
// coordinates buffer. For rings (and closed lines), coordinates[start] equals
// coordinates[end].
//
// For each line or polygon geometry in the input hash, including nested
// geometries as in geometry collections, the `coordinates` array is replaced
// with an equivalent `arcs` array that, for each line (for line string
// geometries) or ring (for polygon geometries), points to one of the above
// lines or rings.
module.exports = function(objects) {
var index = -1,
lines = [],
rings = [],
coordinates = [];
function extractGeometry(geometry) {
if (geometry && extractGeometryType.hasOwnProperty(geometry.type)) extractGeometryType[geometry.type](geometry);
}
var extractGeometryType = {
GeometryCollection: function(o) { o.geometries.forEach(extractGeometry); },
LineString: function(o) { o.arcs = extractLine(o.coordinates); delete o.coordinates; },
MultiLineString: function(o) { o.arcs = o.coordinates.map(extractLine); delete o.coordinates; },
Polygon: function(o) { o.arcs = o.coordinates.map(extractRing); delete o.coordinates; },
MultiPolygon: function(o) { o.arcs = o.coordinates.map(extractMultiRing); delete o.coordinates; }
};
function extractLine(line) {
for (var i = 0, n = line.length; i < n; ++i) coordinates[++index] = line[i];
var arc = {0: index - n + 1, 1: index};
lines.push(arc);
return arc;
}
function extractRing(ring) {
for (var i = 0, n = ring.length; i < n; ++i) coordinates[++index] = ring[i];
var arc = {0: index - n + 1, 1: index};
rings.push(arc);
return arc;
}
function extractMultiRing(rings) {
return rings.map(extractRing);
}
for (var key in objects) {
extractGeometry(objects[key]);
}
return {
type: "Topology",
coordinates: coordinates,
lines: lines,
rings: rings,
objects: objects
};
};
},{}],30:[function(_dereq_,module,exports){
module.exports = function(size, hash, equal) {
var hashtable = new Array(size = 1 << Math.ceil(Math.log(size) / Math.LN2)),
mask = size - 1,
free = size;
function set(key, value) {
var index = hash(key) & mask,
match = hashtable[index],
cycle = !index;
while (match != null) {
if (equal(match.key, key)) return match.value = value;
match = hashtable[index = (index + 1) & mask];
if (!index && cycle++) throw new Error("full hashtable");
}
hashtable[index] = {key: key, value: value};
--free;
return value;
}
function get(key, missingValue) {
var index = hash(key) & mask,
match = hashtable[index],
cycle = !index;
while (match != null) {
if (equal(match.key, key)) return match.value;
match = hashtable[index = (index + 1) & mask];
if (!index && cycle++) break;
}
return missingValue;
}
function remove(key) {
var index = hash(key) & mask,
match = hashtable[index],
cycle = !index;
while (match != null) {
if (equal(match.key, key)) {
hashtable[index] = null;
match = hashtable[index = (index + 1) & mask];
if (match != null) { // delete and re-add
++free;
hashtable[index] = null;
set(match.key, match.value);
}
++free;
return true;
}
match = hashtable[index = (index + 1) & mask];
if (!index && cycle++) break;
}
return false;
}
function keys() {
var keys = [];
for (var i = 0, n = hashtable.length; i < n; ++i) {
var match = hashtable[i];
if (match != null) keys.push(match.key);
}
return keys;
}
return {
set: set,
get: get,
remove: remove,
keys: keys
};
};
},{}],31:[function(_dereq_,module,exports){
var hashtable = _dereq_("./hashtable"),
extract = _dereq_("./extract"),
cut = _dereq_("./cut"),
dedup = _dereq_("./dedup");
// Constructs the TopoJSON Topology for the specified hash of geometries.
// Each object in the specified hash must be a GeoJSON object,
// meaning FeatureCollection, a Feature or a geometry object.
module.exports = function(objects) {
var topology = dedup(cut(extract(objects))),
coordinates = topology.coordinates,
indexByArc = hashtable(topology.arcs.length, hashArc, equalArc);
objects = topology.objects; // for garbage collection
topology.arcs = topology.arcs.map(function(arc, i) {
indexByArc.set(arc, i);
return coordinates.slice(arc[0], arc[1] + 1);
});
delete topology.coordinates;
coordinates = null;
function indexGeometry(geometry) {
if (geometry && indexGeometryType.hasOwnProperty(geometry.type)) indexGeometryType[geometry.type](geometry);
}
var indexGeometryType = {
GeometryCollection: function(o) { o.geometries.forEach(indexGeometry); },
LineString: function(o) { o.arcs = indexArcs(o.arcs); },
MultiLineString: function(o) { o.arcs = o.arcs.map(indexArcs); },
Polygon: function(o) { o.arcs = o.arcs.map(indexArcs); },
MultiPolygon: function(o) { o.arcs = o.arcs.map(indexMultiArcs); }
};
function indexArcs(arc) {
var indexes = [];
do {
var index = indexByArc.get(arc);
indexes.push(arc[0] < arc[1] ? index : ~index);
} while (arc = arc.next);
return indexes;
}
function indexMultiArcs(arcs) {
return arcs.map(indexArcs);
}
for (var key in objects) {
indexGeometry(objects[key]);
}
return topology;
};
function hashArc(arc) {
var i = arc[0], j = arc[1], t;
if (j < i) t = i, i = j, j = t;
return i + 31 * j;
}
function equalArc(arcA, arcB) {
var ia = arcA[0], ja = arcA[1],
ib = arcB[0], jb = arcB[1], t;
if (ja < ia) t = ia, ia = ja, ja = t;
if (jb < ib) t = ib, ib = jb, jb = t;
return ia === ib && ja === jb;
}
},{"./cut":27,"./dedup":28,"./extract":29,"./hashtable":30}],32:[function(_dereq_,module,exports){
var hashtable = _dereq_("./hashtable"),
hashPoint = _dereq_("./point-hash"),
equalPoint = _dereq_("./point-equal");
// Given an extracted (pre-)topology, identifies all of the junctions. These are
// the points at which arcs (lines or rings) will need to be cut so that each
// arc is represented uniquely.
//
// A junction is a point where at least one arc deviates from another arc going
// through the same point. For example, consider the point B. If there is a arc
// through ABC and another arc through CBA, then B is not a junction because in
// both cases the adjacent point pairs are {A,C}. However, if there is an
// additional arc ABD, then {A,D} != {A,C}, and thus B becomes a junction.
//
// For a closed ring ABCA, the first point As adjacent points are the second
// and last point {B,C}. For a line, the first and last point are always
// considered junctions, even if the line is closed; this ensures that a closed
// line is never rotated.
module.exports = function(topology) {
var coordinates = topology.coordinates,
lines = topology.lines,
rings = topology.rings,
visitedByPoint,
neighborsByPoint = hashtable(coordinates.length, hashPoint, equalPoint),
junctionByPoint = hashtable(coordinates.length, hashPoint, equalPoint);
for (var i = 0, n = lines.length; i < n; ++i) {
var line = lines[i],
lineStart = line[0],
lineEnd = line[1],
previousPoint = null,
currentPoint = coordinates[lineStart],
nextPoint = coordinates[++lineStart];
visitedByPoint = hashtable(lineEnd - lineStart, hashPoint, equalPoint);
junctionByPoint.set(currentPoint, true); // start
while (++lineStart <= lineEnd) {
sequence(previousPoint = currentPoint, currentPoint = nextPoint, nextPoint = coordinates[lineStart]);
}
junctionByPoint.set(nextPoint, true); // end
}
for (var i = 0, n = rings.length; i < n; ++i) {
var ring = rings[i],
ringStart = ring[0] + 1,
ringEnd = ring[1],
previousPoint = coordinates[ringEnd - 1],
currentPoint = coordinates[ringStart - 1],
nextPoint = coordinates[ringStart];
visitedByPoint = hashtable(ringEnd - ringStart + 1, hashPoint, equalPoint);
sequence(previousPoint, currentPoint, nextPoint);
while (++ringStart <= ringEnd) {
sequence(previousPoint = currentPoint, currentPoint = nextPoint, nextPoint = coordinates[ringStart]);
}
}
function sequence(previousPoint, currentPoint, nextPoint) {
if (visitedByPoint.get(currentPoint)) return; // ignore self-intersection
visitedByPoint.set(currentPoint, true);
var neighbors = neighborsByPoint.get(currentPoint);
if (neighbors) {
if (!(equalPoint(neighbors[0], previousPoint)
&& equalPoint(neighbors[1], nextPoint))
&& !(equalPoint(neighbors[0], nextPoint)
&& equalPoint(neighbors[1], previousPoint))) {
junctionByPoint.set(currentPoint, true);
}
} else {
neighborsByPoint.set(currentPoint, [previousPoint, nextPoint]);
}
}
return junctionByPoint;
};
},{"./hashtable":30,"./point-equal":33,"./point-hash":34}],33:[function(_dereq_,module,exports){
module.exports = function(pointA, pointB) {
return pointA[0] === pointB[0] && pointA[1] === pointB[1];
};
},{}],34:[function(_dereq_,module,exports){
// TODO if quantized, use simpler Int32 hashing?
var hashBuffer = new ArrayBuffer(8),
hashFloats = new Float64Array(hashBuffer),
hashInts = new Int32Array(hashBuffer);
function hashFloat(x) {
hashFloats[0] = x;
x = hashInts[1] ^ hashInts[0];
x ^= (x >>> 20) ^ (x >>> 12);
x ^= (x >>> 7) ^ (x >>> 4);
return x;
}
module.exports = function(point) {
var h = (hashFloat(point[0]) + 31 * hashFloat(point[1])) | 0;
return h < 0 ? ~h : h;
};
},{}],35:[function(_dereq_,module,exports){
// Given a hash of GeoJSON objects, transforms any properties on features using
// the specified transform function. The function is invoked for each existing
// property on the current feature, being passed the new properties hash, the
// property name, and the property value. The function is then expected to
// assign a new value to the given property hash if the feature is to be
// retained and return true. Or, to skip the property, do nothing and return
// false. If no properties are propagated to the new properties hash, the
// properties hash will be deleted from the current feature.
module.exports = function(objects, propertyTransform) {
if (arguments.length < 2) propertyTransform = function() {};
function transformObject(object) {
if (object && transformObjectType.hasOwnProperty(object.type)) transformObjectType[object.type](object);
}
function transformFeature(feature) {
if (feature.properties) {
var properties0 = feature.properties,
properties1 = {},
empty = true;
for (var key0 in properties0) {
if (propertyTransform(properties1, key0, properties0[key0])) {
empty = false;
}
}
if (empty) delete feature.properties;
else feature.properties = properties1;
}
}
var transformObjectType = {
Feature: transformFeature,
FeatureCollection: function(collection) { collection.features.forEach(transformFeature); }
};
for (var key in objects) {
transformObject(objects[key]);
}
return objects;
};
},{}],36:[function(_dereq_,module,exports){
module.exports = function(types) {
for (var type in typeDefaults) {
if (!(type in types)) {
types[type] = typeDefaults[type];
}
}
types.defaults = typeDefaults;
return types;
};
var typeDefaults = {
Feature: function(feature) {
if (feature.geometry) this.geometry(feature.geometry);
},
FeatureCollection: function(collection) {
var features = collection.features, i = -1, n = features.length;
while (++i < n) this.Feature(features[i]);
},
GeometryCollection: function(collection) {
var geometries = collection.geometries, i = -1, n = geometries.length;
while (++i < n) this.geometry(geometries[i]);
},
LineString: function(lineString) {
this.line(lineString.coordinates);
},
MultiLineString: function(multiLineString) {
var coordinates = multiLineString.coordinates, i = -1, n = coordinates.length;
while (++i < n) this.line(coordinates[i]);
},
MultiPoint: function(multiPoint) {
var coordinates = multiPoint.coordinates, i = -1, n = coordinates.length;
while (++i < n) this.point(coordinates[i]);
},
MultiPolygon: function(multiPolygon) {
var coordinates = multiPolygon.coordinates, i = -1, n = coordinates.length;
while (++i < n) this.polygon(coordinates[i]);
},
Point: function(point) {
this.point(point.coordinates);
},
Polygon: function(polygon) {
this.polygon(polygon.coordinates);
},
object: function(object) {
return object == null ? null
: typeObjects.hasOwnProperty(object.type) ? this[object.type](object)
: this.geometry(object);
},
geometry: function(geometry) {
return geometry == null ? null
: typeGeometries.hasOwnProperty(geometry.type) ? this[geometry.type](geometry)
: null;
},
point: function() {},
line: function(coordinates) {
var i = -1, n = coordinates.length;
while (++i < n) this.point(coordinates[i]);
},
polygon: function(coordinates) {
var i = -1, n = coordinates.length;
while (++i < n) this.line(coordinates[i]);
}
};
var typeGeometries = {
LineString: 1,
MultiLineString: 1,
MultiPoint: 1,
MultiPolygon: 1,
Point: 1,
Polygon: 1,
GeometryCollection: 1
};
var typeObjects = {
Feature: 1,
FeatureCollection: 1
};
},{}],37:[function(_dereq_,module,exports){
!function() {
var topojson = {
version: "1.4.6",
mesh: mesh,
feature: featureOrCollection,
neighbors: neighbors,
presimplify: presimplify
};
function merge(topology, arcs) {
var fragmentByStart = {},
fragmentByEnd = {};
arcs.forEach(function(i) {
var e = ends(i),
start = e[0],
end = e[1],
f, g;
if (f = fragmentByEnd[start]) {
delete fragmentByEnd[f.end];
f.push(i);
f.end = end;
if (g = fragmentByStart[end]) {
delete fragmentByStart[g.start];
var fg = g === f ? f : f.concat(g);
fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.end] = fg;
} else if (g = fragmentByEnd[end]) {
delete fragmentByStart[g.start];
delete fragmentByEnd[g.end];
var fg = f.concat(g.map(function(i) { return ~i; }).reverse());
fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.start] = fg;
} else {
fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
}
} else if (f = fragmentByStart[end]) {
delete fragmentByStart[f.start];
f.unshift(i);
f.start = start;
if (g = fragmentByEnd[start]) {
delete fragmentByEnd[g.end];
var gf = g === f ? f : g.concat(f);
fragmentByStart[gf.start = g.start] = fragmentByEnd[gf.end = f.end] = gf;
} else if (g = fragmentByStart[start]) {
delete fragmentByStart[g.start];
delete fragmentByEnd[g.end];
var gf = g.map(function(i) { return ~i; }).reverse().concat(f);
fragmentByStart[gf.start = g.end] = fragmentByEnd[gf.end = f.end] = gf;
} else {
fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
}
} else if (f = fragmentByStart[start]) {
delete fragmentByStart[f.start];
f.unshift(~i);
f.start = end;
if (g = fragmentByEnd[end]) {
delete fragmentByEnd[g.end];
var gf = g === f ? f : g.concat(f);
fragmentByStart[gf.start = g.start] = fragmentByEnd[gf.end = f.end] = gf;
} else if (g = fragmentByStart[end]) {
delete fragmentByStart[g.start];
delete fragmentByEnd[g.end];
var gf = g.map(function(i) { return ~i; }).reverse().concat(f);
fragmentByStart[gf.start = g.end] = fragmentByEnd[gf.end = f.end] = gf;
} else {
fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
}
} else if (f = fragmentByEnd[end]) {
delete fragmentByEnd[f.end];
f.push(~i);
f.end = start;
if (g = fragmentByEnd[start]) {
delete fragmentByStart[g.start];
var fg = g === f ? f : f.concat(g);
fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.end] = fg;
} else if (g = fragmentByStart[start]) {
delete fragmentByStart[g.start];
delete fragmentByEnd[g.end];
var fg = f.concat(g.map(function(i) { return ~i; }).reverse());
fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.start] = fg;
} else {
fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
}
} else {
f = [i];
fragmentByStart[f.start = start] = fragmentByEnd[f.end = end] = f;
}
});
function ends(i) {
var arc = topology.arcs[i], p0 = arc[0], p1 = [0, 0];
arc.forEach(function(dp) { p1[0] += dp[0], p1[1] += dp[1]; });
return [p0, p1];
}
var fragments = [];
for (var k in fragmentByEnd) fragments.push(fragmentByEnd[k]);
return fragments;
}
function mesh(topology, o, filter) {
var arcs = [];
if (arguments.length > 1) {
var geomsByArc = [],
geom;
function arc(i) {
if (i < 0) i = ~i;
(geomsByArc[i] || (geomsByArc[i] = [])).push(geom);
}
function line(arcs) {
arcs.forEach(arc);
}
function polygon(arcs) {
arcs.forEach(line);
}
function geometry(o) {
if (o.type === "GeometryCollection") o.geometries.forEach(geometry);
else if (o.type in geometryType) {
geom = o;
geometryType[o.type](o.arcs);
}
}
var geometryType = {
LineString: line,
MultiLineString: polygon,
Polygon: polygon,
MultiPolygon: function(arcs) { arcs.forEach(polygon); }
};
geometry(o);
geomsByArc.forEach(arguments.length < 3
? function(geoms, i) { arcs.push(i); }
: function(geoms, i) { if (filter(geoms[0], geoms[geoms.length - 1])) arcs.push(i); });
} else {
for (var i = 0, n = topology.arcs.length; i < n; ++i) arcs.push(i);
}
return object(topology, {type: "MultiLineString", arcs: merge(topology, arcs)});
}
function featureOrCollection(topology, o) {
return o.type === "GeometryCollection" ? {
type: "FeatureCollection",
features: o.geometries.map(function(o) { return feature(topology, o); })
} : feature(topology, o);
}
function feature(topology, o) {
var f = {
type: "Feature",
id: o.id,
properties: o.properties || {},
geometry: object(topology, o)
};
if (o.id == null) delete f.id;
return f;
}
function object(topology, o) {
var absolute = transformAbsolute(topology.transform),
arcs = topology.arcs;
function arc(i, points) {
if (points.length) points.pop();
for (var a = arcs[i < 0 ? ~i : i], k = 0, n = a.length, p; k < n; ++k) {
points.push(p = a[k].slice());
absolute(p, k);
}
if (i < 0) reverse(points, n);
}
function point(p) {
p = p.slice();
absolute(p, 0);
return p;
}
function line(arcs) {
var points = [];
for (var i = 0, n = arcs.length; i < n; ++i) arc(arcs[i], points);
if (points.length < 2) points.push(points[0].slice());
return points;
}
function ring(arcs) {
var points = line(arcs);
while (points.length < 4) points.push(points[0].slice());
return points;
}
function polygon(arcs) {
return arcs.map(ring);
}
function geometry(o) {
var t = o.type;
return t === "GeometryCollection" ? {type: t, geometries: o.geometries.map(geometry)}
: t in geometryType ? {type: t, coordinates: geometryType[t](o)}
: null;
}
var geometryType = {
Point: function(o) { return point(o.coordinates); },
MultiPoint: function(o) { return o.coordinates.map(point); },
LineString: function(o) { return line(o.arcs); },
MultiLineString: function(o) { return o.arcs.map(line); },
Polygon: function(o) { return polygon(o.arcs); },
MultiPolygon: function(o) { return o.arcs.map(polygon); }
};
return geometry(o);
}
function reverse(array, n) {
var t, j = array.length, i = j - n; while (i < --j) t = array[i], array[i++] = array[j], array[j] = t;
}
function bisect(a, x) {
var lo = 0, hi = a.length;
while (lo < hi) {
var mid = lo + hi >>> 1;
if (a[mid] < x) lo = mid + 1;
else hi = mid;
}
return lo;
}
function neighbors(objects) {
var indexesByArc = {}, // arc index -> array of object indexes
neighbors = objects.map(function() { return []; });
function line(arcs, i) {
arcs.forEach(function(a) {
if (a < 0) a = ~a;
var o = indexesByArc[a];
if (o) o.push(i);
else indexesByArc[a] = [i];
});
}
function polygon(arcs, i) {
arcs.forEach(function(arc) { line(arc, i); });
}
function geometry(o, i) {
if (o.type === "GeometryCollection") o.geometries.forEach(function(o) { geometry(o, i); });
else if (o.type in geometryType) geometryType[o.type](o.arcs, i);
}
var geometryType = {
LineString: line,
MultiLineString: polygon,
Polygon: polygon,
MultiPolygon: function(arcs, i) { arcs.forEach(function(arc) { polygon(arc, i); }); }
};
objects.forEach(geometry);
for (var i in indexesByArc) {
for (var indexes = indexesByArc[i], m = indexes.length, j = 0; j < m; ++j) {
for (var k = j + 1; k < m; ++k) {
var ij = indexes[j], ik = indexes[k], n;
if ((n = neighbors[ij])[i = bisect(n, ik)] !== ik) n.splice(i, 0, ik);
if ((n = neighbors[ik])[i = bisect(n, ij)] !== ij) n.splice(i, 0, ij);
}
}
}
return neighbors;
}
function presimplify(topology, triangleArea) {
var absolute = transformAbsolute(topology.transform),
relative = transformRelative(topology.transform),
heap = minHeap(compareArea),
maxArea = 0,
triangle;
if (!triangleArea) triangleArea = cartesianArea;
topology.arcs.forEach(function(arc) {
var triangles = [];
arc.forEach(absolute);
for (var i = 1, n = arc.length - 1; i < n; ++i) {
triangle = arc.slice(i - 1, i + 2);
triangle[1][2] = triangleArea(triangle);
triangles.push(triangle);
heap.push(triangle);
}
// Always keep the arc endpoints!
arc[0][2] = arc[n][2] = Infinity;
for (var i = 0, n = triangles.length; i < n; ++i) {
triangle = triangles[i];
triangle.previous = triangles[i - 1];
triangle.next = triangles[i + 1];
}
});
while (triangle = heap.pop()) {
var previous = triangle.previous,
next = triangle.next;
// If the area of the current point is less than that of the previous point
// to be eliminated, use the latter's area instead. This ensures that the
// current point cannot be eliminated without eliminating previously-
// eliminated points.
if (triangle[1][2] < maxArea) triangle[1][2] = maxArea;
else maxArea = triangle[1][2];
if (previous) {
previous.next = next;
previous[2] = triangle[2];
update(previous);
}
if (next) {
next.previous = previous;
next[0] = triangle[0];
update(next);
}
}
topology.arcs.forEach(function(arc) {
arc.forEach(relative);
});
function update(triangle) {
heap.remove(triangle);
triangle[1][2] = triangleArea(triangle);
heap.push(triangle);
}
return topology;
};
function cartesianArea(triangle) {
return Math.abs(
(triangle[0][0] - triangle[2][0]) * (triangle[1][1] - triangle[0][1])
- (triangle[0][0] - triangle[1][0]) * (triangle[2][1] - triangle[0][1])
);
}
function compareArea(a, b) {
return a[1][2] - b[1][2];
}
function minHeap(compare) {
var heap = {},
array = [];
heap.push = function() {
for (var i = 0, n = arguments.length; i < n; ++i) {
var object = arguments[i];
up(object.index = array.push(object) - 1);
}
return array.length;
};
heap.pop = function() {
var removed = array[0],
object = array.pop();
if (array.length) {
array[object.index = 0] = object;
down(0);
}
return removed;
};
heap.remove = function(removed) {
var i = removed.index,
object = array.pop();
if (i !== array.length) {
array[object.index = i] = object;
(compare(object, removed) < 0 ? up : down)(i);
}
return i;
};
function up(i) {
var object = array[i];
while (i > 0) {
var up = ((i + 1) >> 1) - 1,
parent = array[up];
if (compare(object, parent) >= 0) break;
array[parent.index = i] = parent;
array[object.index = i = up] = object;
}
}
function down(i) {
var object = array[i];
while (true) {
var right = (i + 1) << 1,
left = right - 1,
down = i,
child = array[down];
if (left < array.length && compare(array[left], child) < 0) child = array[down = left];
if (right < array.length && compare(array[right], child) < 0) child = array[down = right];
if (down === i) break;
array[child.index = i] = child;
array[object.index = i = down] = object;
}
}
return heap;
}
function transformAbsolute(transform) {
if (!transform) return noop;
var x0,
y0,
kx = transform.scale[0],
ky = transform.scale[1],
dx = transform.translate[0],
dy = transform.translate[1];
return function(point, i) {
if (!i) x0 = y0 = 0;
point[0] = (x0 += point[0]) * kx + dx;
point[1] = (y0 += point[1]) * ky + dy;
};
}
function transformRelative(transform) {
if (!transform) return noop;
var x0,
y0,
kx = transform.scale[0],
ky = transform.scale[1],
dx = transform.translate[0],
dy = transform.translate[1];
return function(point, i) {
if (!i) x0 = y0 = 0;
var x1 = (point[0] - dx) / kx | 0,
y1 = (point[1] - dy) / ky | 0;
point[0] = x1 - x0;
point[1] = y1 - y0;
x0 = x1;
y0 = y1;
};
}
function noop() {}
if (typeof define === "function" && define.amd) define(topojson);
else if (typeof module === "object" && module.exports) module.exports = topojson;
else this.topojson = topojson;
}();
},{}],38:[function(_dereq_,module,exports){
module.exports = parse;
/*
* Parse WKT and return GeoJSON.
*
* @param {string} _ A WKT geometry
* @return {?Object} A GeoJSON geometry object
*/
function parse(_) {
var i = 0;
function $(re) {
var match = _.substring(i).match(re);
if (!match) return null;
else {
i += match[0].length;
return match[0];
}
}
function white() { $(/^\s*/); }
function multicoords() {
white();
var depth = 0, rings = [],
pointer = rings, elem;
while (elem =
$(/^(\()/) ||
$(/^(\))/) ||
$(/^(\,)/) ||
coords()) {
if (elem == '(') {
depth++;
} else if (elem == ')') {
depth--;
if (depth == 0) break;
} else if (elem && Array.isArray(elem) && elem.length) {
pointer.push(elem);
} else if (elem === ',') {
}
white();
}
if (depth !== 0) return null;
return rings;
}
function coords() {
var list = [], item, pt;
while (pt =
$(/^[-+]?([0-9]*\.[0-9]+|[0-9]+)/) ||
$(/^(\,)/)) {
if (pt == ',') {
list.push(item);
item = [];
} else {
if (!item) item = [];
item.push(parseFloat(pt));
}
white();
}
if (item) list.push(item);
return list.length ? list : null;
}
function point() {
if (!$(/^(point)/i)) return null;
white();
if (!$(/^(\()/)) return null;
var c = coords();
white();
if (!$(/^(\))/)) return null;
return {
type: 'Point',
coordinates: c[0]
};
}
function multipoint() {
if (!$(/^(multipoint)/i)) return null;
white();
var c = multicoords();
white();
return {
type: 'MultiPoint',
coordinates: c[0]
};
}
function multilinestring() {
if (!$(/^(multilinestring)/i)) return null;
white();
var c = multicoords();
white();
return {
type: 'MultiLineString',
coordinates: c
};
}
function linestring() {
if (!$(/^(linestring)/i)) return null;
white();
if (!$(/^(\()/)) return null;
var c = coords();
if (!$(/^(\))/)) return null;
return {
type: 'LineString',
coordinates: c
};
}
function polygon() {
if (!$(/^(polygon)/i)) return null;
white();
return {
type: 'Polygon',
coordinates: multicoords()
};
}
function multipolygon() {
if (!$(/^(multipolygon)/i)) return null;
white();
return {
type: 'MultiPolygon',
coordinates: multicoords()
};
}
function geometrycollection() {
var geometries = [], geometry;
if (!$(/^(geometrycollection)/i)) return null;
white();
if (!$(/^(\()/)) return null;
while (geometry = root()) {
geometries.push(geometry);
white();
$(/^(\,)/);
white();
}
if (!$(/^(\))/)) return null;
return {
type: 'GeometryCollection',
geometries: geometries
};
}
function root() {
return point() ||
linestring() ||
polygon() ||
multipoint() ||
multilinestring() ||
multipolygon() ||
geometrycollection();
}
return root();
}
},{}]},{},[1])
(1)
});