3278 lines
102 KiB
JavaScript
3278 lines
102 KiB
JavaScript
!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 Cagnoli’s
|
||
// theorem. See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
|
||
var dλ = λ - λ0,
|
||
cosφ = Math.cos(φ),
|
||
sinφ = Math.sin(φ),
|
||
k = sinφ0 * sinφ,
|
||
u = cosφ0 * cosφ + k * Math.cos(dλ),
|
||
v = k * Math.sin(dλ);
|
||
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 doesn’t 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 don’t 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 A’s 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)
|
||
});
|