stitch.js 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. export default function(topology, arcs) {
  2. var stitchedArcs = {},
  3. fragmentByStart = {},
  4. fragmentByEnd = {},
  5. fragments = [],
  6. emptyIndex = -1;
  7. // Stitch empty arcs first, since they may be subsumed by other arcs.
  8. arcs.forEach(function(i, j) {
  9. var arc = topology.arcs[i < 0 ? ~i : i], t;
  10. if (arc.length < 3 && !arc[1][0] && !arc[1][1]) {
  11. t = arcs[++emptyIndex], arcs[emptyIndex] = i, arcs[j] = t;
  12. }
  13. });
  14. arcs.forEach(function(i) {
  15. var e = ends(i),
  16. start = e[0],
  17. end = e[1],
  18. f, g;
  19. if (f = fragmentByEnd[start]) {
  20. delete fragmentByEnd[f.end];
  21. f.push(i);
  22. f.end = end;
  23. if (g = fragmentByStart[end]) {
  24. delete fragmentByStart[g.start];
  25. var fg = g === f ? f : f.concat(g);
  26. fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.end] = fg;
  27. } else {
  28. fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
  29. }
  30. } else if (f = fragmentByStart[end]) {
  31. delete fragmentByStart[f.start];
  32. f.unshift(i);
  33. f.start = start;
  34. if (g = fragmentByEnd[start]) {
  35. delete fragmentByEnd[g.end];
  36. var gf = g === f ? f : g.concat(f);
  37. fragmentByStart[gf.start = g.start] = fragmentByEnd[gf.end = f.end] = gf;
  38. } else {
  39. fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
  40. }
  41. } else {
  42. f = [i];
  43. fragmentByStart[f.start = start] = fragmentByEnd[f.end = end] = f;
  44. }
  45. });
  46. function ends(i) {
  47. var arc = topology.arcs[i < 0 ? ~i : i], p0 = arc[0], p1;
  48. if (topology.transform) p1 = [0, 0], arc.forEach(function(dp) { p1[0] += dp[0], p1[1] += dp[1]; });
  49. else p1 = arc[arc.length - 1];
  50. return i < 0 ? [p1, p0] : [p0, p1];
  51. }
  52. function flush(fragmentByEnd, fragmentByStart) {
  53. for (var k in fragmentByEnd) {
  54. var f = fragmentByEnd[k];
  55. delete fragmentByStart[f.start];
  56. delete f.start;
  57. delete f.end;
  58. f.forEach(function(i) { stitchedArcs[i < 0 ? ~i : i] = 1; });
  59. fragments.push(f);
  60. }
  61. }
  62. flush(fragmentByEnd, fragmentByStart);
  63. flush(fragmentByStart, fragmentByEnd);
  64. arcs.forEach(function(i) { if (!stitchedArcs[i < 0 ? ~i : i]) fragments.push([i]); });
  65. return fragments;
  66. }