topojson.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. !function() {
  2. var topojson = {
  3. version: "1.6.20",
  4. mesh: function(topology) { return object(topology, meshArcs.apply(this, arguments)); },
  5. meshArcs: meshArcs,
  6. merge: function(topology) { return object(topology, mergeArcs.apply(this, arguments)); },
  7. mergeArcs: mergeArcs,
  8. feature: featureOrCollection,
  9. neighbors: neighbors,
  10. presimplify: presimplify
  11. };
  12. function stitchArcs(topology, arcs) {
  13. var stitchedArcs = {},
  14. fragmentByStart = {},
  15. fragmentByEnd = {},
  16. fragments = [],
  17. emptyIndex = -1;
  18. // Stitch empty arcs first, since they may be subsumed by other arcs.
  19. arcs.forEach(function(i, j) {
  20. var arc = topology.arcs[i < 0 ? ~i : i], t;
  21. if (arc.length < 3 && !arc[1][0] && !arc[1][1]) {
  22. t = arcs[++emptyIndex], arcs[emptyIndex] = i, arcs[j] = t;
  23. }
  24. });
  25. arcs.forEach(function(i) {
  26. var e = ends(i),
  27. start = e[0],
  28. end = e[1],
  29. f, g;
  30. if (f = fragmentByEnd[start]) {
  31. delete fragmentByEnd[f.end];
  32. f.push(i);
  33. f.end = end;
  34. if (g = fragmentByStart[end]) {
  35. delete fragmentByStart[g.start];
  36. var fg = g === f ? f : f.concat(g);
  37. fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.end] = fg;
  38. } else {
  39. fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
  40. }
  41. } else if (f = fragmentByStart[end]) {
  42. delete fragmentByStart[f.start];
  43. f.unshift(i);
  44. f.start = start;
  45. if (g = fragmentByEnd[start]) {
  46. delete fragmentByEnd[g.end];
  47. var gf = g === f ? f : g.concat(f);
  48. fragmentByStart[gf.start = g.start] = fragmentByEnd[gf.end = f.end] = gf;
  49. } else {
  50. fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
  51. }
  52. } else {
  53. f = [i];
  54. fragmentByStart[f.start = start] = fragmentByEnd[f.end = end] = f;
  55. }
  56. });
  57. function ends(i) {
  58. var arc = topology.arcs[i < 0 ? ~i : i], p0 = arc[0], p1;
  59. if (topology.transform) p1 = [0, 0], arc.forEach(function(dp) { p1[0] += dp[0], p1[1] += dp[1]; });
  60. else p1 = arc[arc.length - 1];
  61. return i < 0 ? [p1, p0] : [p0, p1];
  62. }
  63. function flush(fragmentByEnd, fragmentByStart) {
  64. for (var k in fragmentByEnd) {
  65. var f = fragmentByEnd[k];
  66. delete fragmentByStart[f.start];
  67. delete f.start;
  68. delete f.end;
  69. f.forEach(function(i) { stitchedArcs[i < 0 ? ~i : i] = 1; });
  70. fragments.push(f);
  71. }
  72. }
  73. flush(fragmentByEnd, fragmentByStart);
  74. flush(fragmentByStart, fragmentByEnd);
  75. arcs.forEach(function(i) { if (!stitchedArcs[i < 0 ? ~i : i]) fragments.push([i]); });
  76. return fragments;
  77. }
  78. function meshArcs(topology, o, filter) {
  79. var arcs = [];
  80. if (arguments.length > 1) {
  81. var geomsByArc = [],
  82. geom;
  83. function arc(i) {
  84. var j = i < 0 ? ~i : i;
  85. (geomsByArc[j] || (geomsByArc[j] = [])).push({i: i, g: geom});
  86. }
  87. function line(arcs) {
  88. arcs.forEach(arc);
  89. }
  90. function polygon(arcs) {
  91. arcs.forEach(line);
  92. }
  93. function geometry(o) {
  94. if (o.type === "GeometryCollection") o.geometries.forEach(geometry);
  95. else if (o.type in geometryType) geom = o, geometryType[o.type](o.arcs);
  96. }
  97. var geometryType = {
  98. LineString: line,
  99. MultiLineString: polygon,
  100. Polygon: polygon,
  101. MultiPolygon: function(arcs) { arcs.forEach(polygon); }
  102. };
  103. geometry(o);
  104. geomsByArc.forEach(arguments.length < 3
  105. ? function(geoms) { arcs.push(geoms[0].i); }
  106. : function(geoms) { if (filter(geoms[0].g, geoms[geoms.length - 1].g)) arcs.push(geoms[0].i); });
  107. } else {
  108. for (var i = 0, n = topology.arcs.length; i < n; ++i) arcs.push(i);
  109. }
  110. return {type: "MultiLineString", arcs: stitchArcs(topology, arcs)};
  111. }
  112. function mergeArcs(topology, objects) {
  113. var polygonsByArc = {},
  114. polygons = [],
  115. components = [];
  116. objects.forEach(function(o) {
  117. if (o.type === "Polygon") register(o.arcs);
  118. else if (o.type === "MultiPolygon") o.arcs.forEach(register);
  119. });
  120. function register(polygon) {
  121. polygon.forEach(function(ring) {
  122. ring.forEach(function(arc) {
  123. (polygonsByArc[arc = arc < 0 ? ~arc : arc] || (polygonsByArc[arc] = [])).push(polygon);
  124. });
  125. });
  126. polygons.push(polygon);
  127. }
  128. function exterior(ring) {
  129. return cartesianRingArea(object(topology, {type: "Polygon", arcs: [ring]}).coordinates[0]) > 0; // TODO allow spherical?
  130. }
  131. polygons.forEach(function(polygon) {
  132. if (!polygon._) {
  133. var component = [],
  134. neighbors = [polygon];
  135. polygon._ = 1;
  136. components.push(component);
  137. while (polygon = neighbors.pop()) {
  138. component.push(polygon);
  139. polygon.forEach(function(ring) {
  140. ring.forEach(function(arc) {
  141. polygonsByArc[arc < 0 ? ~arc : arc].forEach(function(polygon) {
  142. if (!polygon._) {
  143. polygon._ = 1;
  144. neighbors.push(polygon);
  145. }
  146. });
  147. });
  148. });
  149. }
  150. }
  151. });
  152. polygons.forEach(function(polygon) {
  153. delete polygon._;
  154. });
  155. return {
  156. type: "MultiPolygon",
  157. arcs: components.map(function(polygons) {
  158. var arcs = [], n;
  159. // Extract the exterior (unique) arcs.
  160. polygons.forEach(function(polygon) {
  161. polygon.forEach(function(ring) {
  162. ring.forEach(function(arc) {
  163. if (polygonsByArc[arc < 0 ? ~arc : arc].length < 2) {
  164. arcs.push(arc);
  165. }
  166. });
  167. });
  168. });
  169. // Stitch the arcs into one or more rings.
  170. arcs = stitchArcs(topology, arcs);
  171. // If more than one ring is returned,
  172. // at most one of these rings can be the exterior;
  173. // this exterior ring has the same winding order
  174. // as any exterior ring in the original polygons.
  175. if ((n = arcs.length) > 1) {
  176. var sgn = exterior(polygons[0][0]);
  177. for (var i = 0, t; i < n; ++i) {
  178. if (sgn === exterior(arcs[i])) {
  179. t = arcs[0], arcs[0] = arcs[i], arcs[i] = t;
  180. break;
  181. }
  182. }
  183. }
  184. return arcs;
  185. })
  186. };
  187. }
  188. function featureOrCollection(topology, o) {
  189. return o.type === "GeometryCollection" ? {
  190. type: "FeatureCollection",
  191. features: o.geometries.map(function(o) { return feature(topology, o); })
  192. } : feature(topology, o);
  193. }
  194. function feature(topology, o) {
  195. var f = {
  196. type: "Feature",
  197. id: o.id,
  198. properties: o.properties || {},
  199. geometry: object(topology, o)
  200. };
  201. if (o.id == null) delete f.id;
  202. return f;
  203. }
  204. function object(topology, o) {
  205. var absolute = transformAbsolute(topology.transform),
  206. arcs = topology.arcs;
  207. function arc(i, points) {
  208. if (points.length) points.pop();
  209. for (var a = arcs[i < 0 ? ~i : i], k = 0, n = a.length, p; k < n; ++k) {
  210. points.push(p = a[k].slice());
  211. absolute(p, k);
  212. }
  213. if (i < 0) reverse(points, n);
  214. }
  215. function point(p) {
  216. p = p.slice();
  217. absolute(p, 0);
  218. return p;
  219. }
  220. function line(arcs) {
  221. var points = [];
  222. for (var i = 0, n = arcs.length; i < n; ++i) arc(arcs[i], points);
  223. if (points.length < 2) points.push(points[0].slice());
  224. return points;
  225. }
  226. function ring(arcs) {
  227. var points = line(arcs);
  228. while (points.length < 4) points.push(points[0].slice());
  229. return points;
  230. }
  231. function polygon(arcs) {
  232. return arcs.map(ring);
  233. }
  234. function geometry(o) {
  235. var t = o.type;
  236. return t === "GeometryCollection" ? {type: t, geometries: o.geometries.map(geometry)}
  237. : t in geometryType ? {type: t, coordinates: geometryType[t](o)}
  238. : null;
  239. }
  240. var geometryType = {
  241. Point: function(o) { return point(o.coordinates); },
  242. MultiPoint: function(o) { return o.coordinates.map(point); },
  243. LineString: function(o) { return line(o.arcs); },
  244. MultiLineString: function(o) { return o.arcs.map(line); },
  245. Polygon: function(o) { return polygon(o.arcs); },
  246. MultiPolygon: function(o) { return o.arcs.map(polygon); }
  247. };
  248. return geometry(o);
  249. }
  250. function reverse(array, n) {
  251. var t, j = array.length, i = j - n; while (i < --j) t = array[i], array[i++] = array[j], array[j] = t;
  252. }
  253. function bisect(a, x) {
  254. var lo = 0, hi = a.length;
  255. while (lo < hi) {
  256. var mid = lo + hi >>> 1;
  257. if (a[mid] < x) lo = mid + 1;
  258. else hi = mid;
  259. }
  260. return lo;
  261. }
  262. function neighbors(objects) {
  263. var indexesByArc = {}, // arc index -> array of object indexes
  264. neighbors = objects.map(function() { return []; });
  265. function line(arcs, i) {
  266. arcs.forEach(function(a) {
  267. if (a < 0) a = ~a;
  268. var o = indexesByArc[a];
  269. if (o) o.push(i);
  270. else indexesByArc[a] = [i];
  271. });
  272. }
  273. function polygon(arcs, i) {
  274. arcs.forEach(function(arc) { line(arc, i); });
  275. }
  276. function geometry(o, i) {
  277. if (o.type === "GeometryCollection") o.geometries.forEach(function(o) { geometry(o, i); });
  278. else if (o.type in geometryType) geometryType[o.type](o.arcs, i);
  279. }
  280. var geometryType = {
  281. LineString: line,
  282. MultiLineString: polygon,
  283. Polygon: polygon,
  284. MultiPolygon: function(arcs, i) { arcs.forEach(function(arc) { polygon(arc, i); }); }
  285. };
  286. objects.forEach(geometry);
  287. for (var i in indexesByArc) {
  288. for (var indexes = indexesByArc[i], m = indexes.length, j = 0; j < m; ++j) {
  289. for (var k = j + 1; k < m; ++k) {
  290. var ij = indexes[j], ik = indexes[k], n;
  291. if ((n = neighbors[ij])[i = bisect(n, ik)] !== ik) n.splice(i, 0, ik);
  292. if ((n = neighbors[ik])[i = bisect(n, ij)] !== ij) n.splice(i, 0, ij);
  293. }
  294. }
  295. }
  296. return neighbors;
  297. }
  298. function presimplify(topology, triangleArea) {
  299. var absolute = transformAbsolute(topology.transform),
  300. relative = transformRelative(topology.transform),
  301. heap = minAreaHeap();
  302. if (!triangleArea) triangleArea = cartesianTriangleArea;
  303. topology.arcs.forEach(function(arc) {
  304. var triangles = [],
  305. maxArea = 0,
  306. triangle;
  307. // To store each point’s effective area, we create a new array rather than
  308. // extending the passed-in point to workaround a Chrome/V8 bug (getting
  309. // stuck in smi mode). For midpoints, the initial effective area of
  310. // Infinity will be computed in the next step.
  311. for (var i = 0, n = arc.length, p; i < n; ++i) {
  312. p = arc[i];
  313. absolute(arc[i] = [p[0], p[1], Infinity], i);
  314. }
  315. for (var i = 1, n = arc.length - 1; i < n; ++i) {
  316. triangle = arc.slice(i - 1, i + 2);
  317. triangle[1][2] = triangleArea(triangle);
  318. triangles.push(triangle);
  319. heap.push(triangle);
  320. }
  321. for (var i = 0, n = triangles.length; i < n; ++i) {
  322. triangle = triangles[i];
  323. triangle.previous = triangles[i - 1];
  324. triangle.next = triangles[i + 1];
  325. }
  326. while (triangle = heap.pop()) {
  327. var previous = triangle.previous,
  328. next = triangle.next;
  329. // If the area of the current point is less than that of the previous point
  330. // to be eliminated, use the latter's area instead. This ensures that the
  331. // current point cannot be eliminated without eliminating previously-
  332. // eliminated points.
  333. if (triangle[1][2] < maxArea) triangle[1][2] = maxArea;
  334. else maxArea = triangle[1][2];
  335. if (previous) {
  336. previous.next = next;
  337. previous[2] = triangle[2];
  338. update(previous);
  339. }
  340. if (next) {
  341. next.previous = previous;
  342. next[0] = triangle[0];
  343. update(next);
  344. }
  345. }
  346. arc.forEach(relative);
  347. });
  348. function update(triangle) {
  349. heap.remove(triangle);
  350. triangle[1][2] = triangleArea(triangle);
  351. heap.push(triangle);
  352. }
  353. return topology;
  354. }
  355. function cartesianRingArea(ring) {
  356. var i = -1,
  357. n = ring.length,
  358. a,
  359. b = ring[n - 1],
  360. area = 0;
  361. while (++i < n) {
  362. a = b;
  363. b = ring[i];
  364. area += a[0] * b[1] - a[1] * b[0];
  365. }
  366. return area / 2;
  367. }
  368. function cartesianTriangleArea(triangle) {
  369. var a = triangle[0], b = triangle[1], c = triangle[2];
  370. return Math.abs((a[0] - c[0]) * (b[1] - a[1]) - (a[0] - b[0]) * (c[1] - a[1]));
  371. }
  372. function compareArea(a, b) {
  373. return a[1][2] - b[1][2];
  374. }
  375. function minAreaHeap() {
  376. var heap = {},
  377. array = [],
  378. size = 0;
  379. heap.push = function(object) {
  380. up(array[object._ = size] = object, size++);
  381. return size;
  382. };
  383. heap.pop = function() {
  384. if (size <= 0) return;
  385. var removed = array[0], object;
  386. if (--size > 0) object = array[size], down(array[object._ = 0] = object, 0);
  387. return removed;
  388. };
  389. heap.remove = function(removed) {
  390. var i = removed._, object;
  391. if (array[i] !== removed) return; // invalid request
  392. if (i !== --size) object = array[size], (compareArea(object, removed) < 0 ? up : down)(array[object._ = i] = object, i);
  393. return i;
  394. };
  395. function up(object, i) {
  396. while (i > 0) {
  397. var j = ((i + 1) >> 1) - 1,
  398. parent = array[j];
  399. if (compareArea(object, parent) >= 0) break;
  400. array[parent._ = i] = parent;
  401. array[object._ = i = j] = object;
  402. }
  403. }
  404. function down(object, i) {
  405. while (true) {
  406. var r = (i + 1) << 1,
  407. l = r - 1,
  408. j = i,
  409. child = array[j];
  410. if (l < size && compareArea(array[l], child) < 0) child = array[j = l];
  411. if (r < size && compareArea(array[r], child) < 0) child = array[j = r];
  412. if (j === i) break;
  413. array[child._ = i] = child;
  414. array[object._ = i = j] = object;
  415. }
  416. }
  417. return heap;
  418. }
  419. function transformAbsolute(transform) {
  420. if (!transform) return noop;
  421. var x0,
  422. y0,
  423. kx = transform.scale[0],
  424. ky = transform.scale[1],
  425. dx = transform.translate[0],
  426. dy = transform.translate[1];
  427. return function(point, i) {
  428. if (!i) x0 = y0 = 0;
  429. point[0] = (x0 += point[0]) * kx + dx;
  430. point[1] = (y0 += point[1]) * ky + dy;
  431. };
  432. }
  433. function transformRelative(transform) {
  434. if (!transform) return noop;
  435. var x0,
  436. y0,
  437. kx = transform.scale[0],
  438. ky = transform.scale[1],
  439. dx = transform.translate[0],
  440. dy = transform.translate[1];
  441. return function(point, i) {
  442. if (!i) x0 = y0 = 0;
  443. var x1 = (point[0] - dx) / kx | 0,
  444. y1 = (point[1] - dy) / ky | 0;
  445. point[0] = x1 - x0;
  446. point[1] = y1 - y0;
  447. x0 = x1;
  448. y0 = y1;
  449. };
  450. }
  451. function noop() {}
  452. if (typeof define === "function" && define.amd) define(topojson);
  453. else if (typeof module === "object" && module.exports) module.exports = topojson;
  454. else this.topojson = topojson;
  455. }();