123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566 |
- /**
- @license
- topojson - https://github.com/mbostock/topojson
- Copyright (c) 2012, Michael Bostock
- All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * The name Michael Bostock may not be used to endorse or promote products
- derived from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
- INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- !function() {
- var topojson = {
- version: "1.6.18",
- mesh: function(topology) { return object(topology, meshArcs.apply(this, arguments)); },
- meshArcs: meshArcs,
- merge: function(topology) { return object(topology, mergeArcs.apply(this, arguments)); },
- mergeArcs: mergeArcs,
- feature: featureOrCollection,
- neighbors: neighbors,
- presimplify: presimplify
- };
- function stitchArcs(topology, arcs) {
- var stitchedArcs = {},
- fragmentByStart = {},
- fragmentByEnd = {},
- fragments = [],
- emptyIndex = -1;
- // Stitch empty arcs first, since they may be subsumed by other arcs.
- arcs.forEach(function(i, j) {
- var arc = topology.arcs[i < 0 ? ~i : i], t;
- if (arc.length < 3 && !arc[1][0] && !arc[1][1]) {
- t = arcs[++emptyIndex], arcs[emptyIndex] = i, arcs[j] = t;
- }
- });
- 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 {
- 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 {
- 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 < 0 ? ~i : i], p0 = arc[0], p1;
- if (topology.transform) p1 = [0, 0], arc.forEach(function(dp) { p1[0] += dp[0], p1[1] += dp[1]; });
- else p1 = arc[arc.length - 1];
- return i < 0 ? [p1, p0] : [p0, p1];
- }
- function flush(fragmentByEnd, fragmentByStart) {
- for (var k in fragmentByEnd) {
- var f = fragmentByEnd[k];
- delete fragmentByStart[f.start];
- delete f.start;
- delete f.end;
- f.forEach(function(i) { stitchedArcs[i < 0 ? ~i : i] = 1; });
- fragments.push(f);
- }
- }
- flush(fragmentByEnd, fragmentByStart);
- flush(fragmentByStart, fragmentByEnd);
- arcs.forEach(function(i) { if (!stitchedArcs[i < 0 ? ~i : i]) fragments.push([i]); });
- return fragments;
- }
- function meshArcs(topology, o, filter) {
- var arcs = [];
- if (arguments.length > 1) {
- var geomsByArc = [],
- geom;
- function arc(i) {
- var j = i < 0 ? ~i : i;
- (geomsByArc[j] || (geomsByArc[j] = [])).push({i: i, g: 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) { arcs.push(geoms[0].i); }
- : function(geoms) { if (filter(geoms[0].g, geoms[geoms.length - 1].g)) arcs.push(geoms[0].i); });
- } else {
- for (var i = 0, n = topology.arcs.length; i < n; ++i) arcs.push(i);
- }
- return {type: "MultiLineString", arcs: stitchArcs(topology, arcs)};
- }
- function mergeArcs(topology, objects) {
- var polygonsByArc = {},
- polygons = [],
- components = [];
- objects.forEach(function(o) {
- if (o.type === "Polygon") register(o.arcs);
- else if (o.type === "MultiPolygon") o.arcs.forEach(register);
- });
- function register(polygon) {
- polygon.forEach(function(ring) {
- ring.forEach(function(arc) {
- (polygonsByArc[arc = arc < 0 ? ~arc : arc] || (polygonsByArc[arc] = [])).push(polygon);
- });
- });
- polygons.push(polygon);
- }
- function exterior(ring) {
- return cartesianRingArea(object(topology, {type: "Polygon", arcs: [ring]}).coordinates[0]) > 0; // TODO allow spherical?
- }
- polygons.forEach(function(polygon) {
- if (!polygon._) {
- var component = [],
- neighbors = [polygon];
- polygon._ = 1;
- components.push(component);
- while (polygon = neighbors.pop()) {
- component.push(polygon);
- polygon.forEach(function(ring) {
- ring.forEach(function(arc) {
- polygonsByArc[arc < 0 ? ~arc : arc].forEach(function(polygon) {
- if (!polygon._) {
- polygon._ = 1;
- neighbors.push(polygon);
- }
- });
- });
- });
- }
- }
- });
- polygons.forEach(function(polygon) {
- delete polygon._;
- });
- return {
- type: "MultiPolygon",
- arcs: components.map(function(polygons) {
- var arcs = [];
- // Extract the exterior (unique) arcs.
- polygons.forEach(function(polygon) {
- polygon.forEach(function(ring) {
- ring.forEach(function(arc) {
- if (polygonsByArc[arc < 0 ? ~arc : arc].length < 2) {
- arcs.push(arc);
- }
- });
- });
- });
- // Stitch the arcs into one or more rings.
- arcs = stitchArcs(topology, arcs);
- // If more than one ring is returned,
- // at most one of these rings can be the exterior;
- // this exterior ring has the same winding order
- // as any exterior ring in the original polygons.
- if ((n = arcs.length) > 1) {
- var sgn = exterior(polygons[0][0]);
- for (var i = 0, t; i < n; ++i) {
- if (sgn === exterior(arcs[i])) {
- t = arcs[0], arcs[0] = arcs[i], arcs[i] = t;
- break;
- }
- }
- }
- return 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 = minAreaHeap();
- if (!triangleArea) triangleArea = cartesianTriangleArea;
- topology.arcs.forEach(function(arc) {
- var triangles = [],
- maxArea = 0,
- triangle;
- // To store each point’s effective area, we create a new array rather than
- // extending the passed-in point to workaround a Chrome/V8 bug (getting
- // stuck in smi mode). For midpoints, the initial effective area of
- // Infinity will be computed in the next step.
- for (var i = 0, n = arc.length, p; i < n; ++i) {
- p = arc[i];
- absolute(arc[i] = [p[0], p[1], Infinity], i);
- }
- 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);
- }
- 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);
- }
- }
- arc.forEach(relative);
- });
- function update(triangle) {
- heap.remove(triangle);
- triangle[1][2] = triangleArea(triangle);
- heap.push(triangle);
- }
- return topology;
- };
- function cartesianRingArea(ring) {
- var i = -1,
- n = ring.length,
- a,
- b = ring[n - 1],
- area = 0;
- while (++i < n) {
- a = b;
- b = ring[i];
- area += a[0] * b[1] - a[1] * b[0];
- }
- return area * .5;
- }
- function cartesianTriangleArea(triangle) {
- var a = triangle[0], b = triangle[1], c = triangle[2];
- return Math.abs((a[0] - c[0]) * (b[1] - a[1]) - (a[0] - b[0]) * (c[1] - a[1]));
- }
- function compareArea(a, b) {
- return a[1][2] - b[1][2];
- }
- function minAreaHeap() {
- var heap = {},
- array = [],
- size = 0;
- heap.push = function(object) {
- up(array[object._ = size] = object, size++);
- return size;
- };
- heap.pop = function() {
- if (size <= 0) return;
- var removed = array[0], object;
- if (--size > 0) object = array[size], down(array[object._ = 0] = object, 0);
- return removed;
- };
- heap.remove = function(removed) {
- var i = removed._, object;
- if (array[i] !== removed) return; // invalid request
- if (i !== --size) object = array[size], (compareArea(object, removed) < 0 ? up : down)(array[object._ = i] = object, i);
- return i;
- };
- function up(object, i) {
- while (i > 0) {
- var j = ((i + 1) >> 1) - 1,
- parent = array[j];
- if (compareArea(object, parent) >= 0) break;
- array[parent._ = i] = parent;
- array[object._ = i = j] = object;
- }
- }
- function down(object, i) {
- while (true) {
- var r = (i + 1) << 1,
- l = r - 1,
- j = i,
- child = array[j];
- if (l < size && compareArea(array[l], child) < 0) child = array[j = l];
- if (r < size && compareArea(array[r], child) < 0) child = array[j = r];
- if (j === i) break;
- array[child._ = i] = child;
- array[object._ = i = j] = 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;
- }();
|