Diagram.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import {addBeach, removeBeach} from "./Beach";
  2. import {sortCellHalfedges, cellHalfedgeStart, clipCells} from "./Cell";
  3. import {firstCircle} from "./Circle";
  4. import {clipEdges} from "./Edge";
  5. import RedBlackTree from "./RedBlackTree";
  6. export var epsilon = 1e-6;
  7. export var epsilon2 = 1e-12;
  8. export var beaches;
  9. export var cells;
  10. export var circles;
  11. export var edges;
  12. function triangleArea(a, b, c) {
  13. return (a[0] - c[0]) * (b[1] - a[1]) - (a[0] - b[0]) * (c[1] - a[1]);
  14. }
  15. function lexicographic(a, b) {
  16. return b[1] - a[1]
  17. || b[0] - a[0];
  18. }
  19. export default function Diagram(sites, extent) {
  20. var site = sites.sort(lexicographic).pop(),
  21. x,
  22. y,
  23. circle;
  24. edges = [];
  25. cells = new Array(sites.length);
  26. beaches = new RedBlackTree;
  27. circles = new RedBlackTree;
  28. while (true) {
  29. circle = firstCircle;
  30. if (site && (!circle || site[1] < circle.y || (site[1] === circle.y && site[0] < circle.x))) {
  31. if (site[0] !== x || site[1] !== y) {
  32. addBeach(site);
  33. x = site[0], y = site[1];
  34. }
  35. site = sites.pop();
  36. } else if (circle) {
  37. removeBeach(circle.arc);
  38. } else {
  39. break;
  40. }
  41. }
  42. sortCellHalfedges();
  43. if (extent) {
  44. var x0 = +extent[0][0],
  45. y0 = +extent[0][1],
  46. x1 = +extent[1][0],
  47. y1 = +extent[1][1];
  48. clipEdges(x0, y0, x1, y1);
  49. clipCells(x0, y0, x1, y1);
  50. }
  51. this.edges = edges;
  52. this.cells = cells;
  53. beaches =
  54. circles =
  55. edges =
  56. cells = null;
  57. }
  58. Diagram.prototype = {
  59. constructor: Diagram,
  60. polygons: function() {
  61. var edges = this.edges;
  62. return this.cells.map(function(cell) {
  63. var polygon = cell.halfedges.map(function(i) { return cellHalfedgeStart(cell, edges[i]); });
  64. polygon.data = cell.site.data;
  65. return polygon;
  66. });
  67. },
  68. triangles: function() {
  69. var triangles = [],
  70. edges = this.edges;
  71. this.cells.forEach(function(cell, i) {
  72. if (!(m = (halfedges = cell.halfedges).length)) return;
  73. var site = cell.site,
  74. halfedges,
  75. j = -1,
  76. m,
  77. s0,
  78. e1 = edges[halfedges[m - 1]],
  79. s1 = e1.left === site ? e1.right : e1.left;
  80. while (++j < m) {
  81. s0 = s1;
  82. e1 = edges[halfedges[j]];
  83. s1 = e1.left === site ? e1.right : e1.left;
  84. if (s0 && s1 && i < s0.index && i < s1.index && triangleArea(site, s0, s1) < 0) {
  85. triangles.push([site.data, s0.data, s1.data]);
  86. }
  87. }
  88. });
  89. return triangles;
  90. },
  91. links: function() {
  92. return this.edges.filter(function(edge) {
  93. return edge.right;
  94. }).map(function(edge) {
  95. return {
  96. source: edge.left.data,
  97. target: edge.right.data
  98. };
  99. });
  100. },
  101. find: function(x, y, radius) {
  102. var that = this, i0, i1 = that._found || 0, n = that.cells.length, cell;
  103. // Use the previously-found cell, or start with an arbitrary one.
  104. while (!(cell = that.cells[i1])) if (++i1 >= n) return null;
  105. var dx = x - cell.site[0], dy = y - cell.site[1], d2 = dx * dx + dy * dy;
  106. // Traverse the half-edges to find a closer cell, if any.
  107. do {
  108. cell = that.cells[i0 = i1], i1 = null;
  109. cell.halfedges.forEach(function(e) {
  110. var edge = that.edges[e], v = edge.left;
  111. if ((v === cell.site || !v) && !(v = edge.right)) return;
  112. var vx = x - v[0], vy = y - v[1], v2 = vx * vx + vy * vy;
  113. if (v2 < d2) d2 = v2, i1 = v.index;
  114. });
  115. } while (i1 !== null);
  116. that._found = i0;
  117. return radius == null || d2 <= radius * radius ? cell.site : null;
  118. }
  119. }