Beach.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. import {RedBlackNode} from "./RedBlackTree";
  2. import {createCell} from "./Cell";
  3. import {attachCircle, detachCircle} from "./Circle";
  4. import {createEdge, setEdgeEnd} from "./Edge";
  5. import {beaches, epsilon} from "./Diagram";
  6. var beachPool = [];
  7. function Beach() {
  8. RedBlackNode(this);
  9. this.edge =
  10. this.site =
  11. this.circle = null;
  12. }
  13. function createBeach(site) {
  14. var beach = beachPool.pop() || new Beach;
  15. beach.site = site;
  16. return beach;
  17. }
  18. function detachBeach(beach) {
  19. detachCircle(beach);
  20. beaches.remove(beach);
  21. beachPool.push(beach);
  22. RedBlackNode(beach);
  23. }
  24. export function removeBeach(beach) {
  25. var circle = beach.circle,
  26. x = circle.x,
  27. y = circle.cy,
  28. vertex = [x, y],
  29. previous = beach.P,
  30. next = beach.N,
  31. disappearing = [beach];
  32. detachBeach(beach);
  33. var lArc = previous;
  34. while (lArc.circle
  35. && Math.abs(x - lArc.circle.x) < epsilon
  36. && Math.abs(y - lArc.circle.cy) < epsilon) {
  37. previous = lArc.P;
  38. disappearing.unshift(lArc);
  39. detachBeach(lArc);
  40. lArc = previous;
  41. }
  42. disappearing.unshift(lArc);
  43. detachCircle(lArc);
  44. var rArc = next;
  45. while (rArc.circle
  46. && Math.abs(x - rArc.circle.x) < epsilon
  47. && Math.abs(y - rArc.circle.cy) < epsilon) {
  48. next = rArc.N;
  49. disappearing.push(rArc);
  50. detachBeach(rArc);
  51. rArc = next;
  52. }
  53. disappearing.push(rArc);
  54. detachCircle(rArc);
  55. var nArcs = disappearing.length,
  56. iArc;
  57. for (iArc = 1; iArc < nArcs; ++iArc) {
  58. rArc = disappearing[iArc];
  59. lArc = disappearing[iArc - 1];
  60. setEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex);
  61. }
  62. lArc = disappearing[0];
  63. rArc = disappearing[nArcs - 1];
  64. rArc.edge = createEdge(lArc.site, rArc.site, null, vertex);
  65. attachCircle(lArc);
  66. attachCircle(rArc);
  67. }
  68. export function addBeach(site) {
  69. var x = site[0],
  70. directrix = site[1],
  71. lArc,
  72. rArc,
  73. dxl,
  74. dxr,
  75. node = beaches._;
  76. while (node) {
  77. dxl = leftBreakPoint(node, directrix) - x;
  78. if (dxl > epsilon) node = node.L; else {
  79. dxr = x - rightBreakPoint(node, directrix);
  80. if (dxr > epsilon) {
  81. if (!node.R) {
  82. lArc = node;
  83. break;
  84. }
  85. node = node.R;
  86. } else {
  87. if (dxl > -epsilon) {
  88. lArc = node.P;
  89. rArc = node;
  90. } else if (dxr > -epsilon) {
  91. lArc = node;
  92. rArc = node.N;
  93. } else {
  94. lArc = rArc = node;
  95. }
  96. break;
  97. }
  98. }
  99. }
  100. createCell(site);
  101. var newArc = createBeach(site);
  102. beaches.insert(lArc, newArc);
  103. if (!lArc && !rArc) return;
  104. if (lArc === rArc) {
  105. detachCircle(lArc);
  106. rArc = createBeach(lArc.site);
  107. beaches.insert(newArc, rArc);
  108. newArc.edge = rArc.edge = createEdge(lArc.site, newArc.site);
  109. attachCircle(lArc);
  110. attachCircle(rArc);
  111. return;
  112. }
  113. if (!rArc) { // && lArc
  114. newArc.edge = createEdge(lArc.site, newArc.site);
  115. return;
  116. }
  117. // else lArc !== rArc
  118. detachCircle(lArc);
  119. detachCircle(rArc);
  120. var lSite = lArc.site,
  121. ax = lSite[0],
  122. ay = lSite[1],
  123. bx = site[0] - ax,
  124. by = site[1] - ay,
  125. rSite = rArc.site,
  126. cx = rSite[0] - ax,
  127. cy = rSite[1] - ay,
  128. d = 2 * (bx * cy - by * cx),
  129. hb = bx * bx + by * by,
  130. hc = cx * cx + cy * cy,
  131. vertex = [(cy * hb - by * hc) / d + ax, (bx * hc - cx * hb) / d + ay];
  132. setEdgeEnd(rArc.edge, lSite, rSite, vertex);
  133. newArc.edge = createEdge(lSite, site, null, vertex);
  134. rArc.edge = createEdge(site, rSite, null, vertex);
  135. attachCircle(lArc);
  136. attachCircle(rArc);
  137. }
  138. function leftBreakPoint(arc, directrix) {
  139. var site = arc.site,
  140. rfocx = site[0],
  141. rfocy = site[1],
  142. pby2 = rfocy - directrix;
  143. if (!pby2) return rfocx;
  144. var lArc = arc.P;
  145. if (!lArc) return -Infinity;
  146. site = lArc.site;
  147. var lfocx = site[0],
  148. lfocy = site[1],
  149. plby2 = lfocy - directrix;
  150. if (!plby2) return lfocx;
  151. var hl = lfocx - rfocx,
  152. aby2 = 1 / pby2 - 1 / plby2,
  153. b = hl / plby2;
  154. if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx;
  155. return (rfocx + lfocx) / 2;
  156. }
  157. function rightBreakPoint(arc, directrix) {
  158. var rArc = arc.N;
  159. if (rArc) return leftBreakPoint(rArc, directrix);
  160. var site = arc.site;
  161. return site[1] === directrix ? site[0] : Infinity;
  162. }