source: node_modules/d3-hierarchy/src/pack/siblings.js@ ba17441

Last change on this file since ba17441 was e4c61dd, checked in by istevanoska <ilinastevanoska@…>, 6 months ago

Prototype 1.1

  • Property mode set to 100644
File size: 3.2 KB
Line 
1import array from "../array.js";
2import lcg from "../lcg.js";
3import {packEncloseRandom} from "./enclose.js";
4
5function place(b, a, c) {
6 var dx = b.x - a.x, x, a2,
7 dy = b.y - a.y, y, b2,
8 d2 = dx * dx + dy * dy;
9 if (d2) {
10 a2 = a.r + c.r, a2 *= a2;
11 b2 = b.r + c.r, b2 *= b2;
12 if (a2 > b2) {
13 x = (d2 + b2 - a2) / (2 * d2);
14 y = Math.sqrt(Math.max(0, b2 / d2 - x * x));
15 c.x = b.x - x * dx - y * dy;
16 c.y = b.y - x * dy + y * dx;
17 } else {
18 x = (d2 + a2 - b2) / (2 * d2);
19 y = Math.sqrt(Math.max(0, a2 / d2 - x * x));
20 c.x = a.x + x * dx - y * dy;
21 c.y = a.y + x * dy + y * dx;
22 }
23 } else {
24 c.x = a.x + c.r;
25 c.y = a.y;
26 }
27}
28
29function intersects(a, b) {
30 var dr = a.r + b.r - 1e-6, dx = b.x - a.x, dy = b.y - a.y;
31 return dr > 0 && dr * dr > dx * dx + dy * dy;
32}
33
34function score(node) {
35 var a = node._,
36 b = node.next._,
37 ab = a.r + b.r,
38 dx = (a.x * b.r + b.x * a.r) / ab,
39 dy = (a.y * b.r + b.y * a.r) / ab;
40 return dx * dx + dy * dy;
41}
42
43function Node(circle) {
44 this._ = circle;
45 this.next = null;
46 this.previous = null;
47}
48
49export function packSiblingsRandom(circles, random) {
50 if (!(n = (circles = array(circles)).length)) return 0;
51
52 var a, b, c, n, aa, ca, i, j, k, sj, sk;
53
54 // Place the first circle.
55 a = circles[0], a.x = 0, a.y = 0;
56 if (!(n > 1)) return a.r;
57
58 // Place the second circle.
59 b = circles[1], a.x = -b.r, b.x = a.r, b.y = 0;
60 if (!(n > 2)) return a.r + b.r;
61
62 // Place the third circle.
63 place(b, a, c = circles[2]);
64
65 // Initialize the front-chain using the first three circles a, b and c.
66 a = new Node(a), b = new Node(b), c = new Node(c);
67 a.next = c.previous = b;
68 b.next = a.previous = c;
69 c.next = b.previous = a;
70
71 // Attempt to place each remaining circle…
72 pack: for (i = 3; i < n; ++i) {
73 place(a._, b._, c = circles[i]), c = new Node(c);
74
75 // Find the closest intersecting circle on the front-chain, if any.
76 // “Closeness” is determined by linear distance along the front-chain.
77 // “Ahead” or “behind” is likewise determined by linear distance.
78 j = b.next, k = a.previous, sj = b._.r, sk = a._.r;
79 do {
80 if (sj <= sk) {
81 if (intersects(j._, c._)) {
82 b = j, a.next = b, b.previous = a, --i;
83 continue pack;
84 }
85 sj += j._.r, j = j.next;
86 } else {
87 if (intersects(k._, c._)) {
88 a = k, a.next = b, b.previous = a, --i;
89 continue pack;
90 }
91 sk += k._.r, k = k.previous;
92 }
93 } while (j !== k.next);
94
95 // Success! Insert the new circle c between a and b.
96 c.previous = a, c.next = b, a.next = b.previous = b = c;
97
98 // Compute the new closest circle pair to the centroid.
99 aa = score(a);
100 while ((c = c.next) !== b) {
101 if ((ca = score(c)) < aa) {
102 a = c, aa = ca;
103 }
104 }
105 b = a.next;
106 }
107
108 // Compute the enclosing circle of the front chain.
109 a = [b._], c = b; while ((c = c.next) !== b) a.push(c._); c = packEncloseRandom(a, random);
110
111 // Translate the circles to put the enclosing circle around the origin.
112 for (i = 0; i < n; ++i) a = circles[i], a.x -= c.x, a.y -= c.y;
113
114 return c.r;
115}
116
117export default function(circles) {
118 packSiblingsRandom(circles, lcg());
119 return circles;
120}
Note: See TracBrowser for help on using the repository browser.