1 | (function (global, factory) {
|
2 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-array'), require('d3-polygon')) :
|
3 | typeof define === 'function' && define.amd ? define(['exports', 'd3-array', 'd3-polygon'], factory) :
|
4 | (factory((global.d3 = global.d3 || {}),global.d3,global.d3));
|
5 | }(this, function (exports,d3Array,d3Polygon) { 'use strict';
|
6 |
|
7 | var epsilon = 1e-10;
|
8 |
|
9 | function epsilonesque(n) {
|
10 | return n <= epsilon && n >= -epsilon;
|
11 | }
|
12 |
|
13 |
|
14 |
|
15 | function dot(v0, v1) {
|
16 | return v0.x * v1.x + v0.y * v1.y + v0.z * v1.z;
|
17 | }
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | function linearDependent(v0, v1) {
|
23 | return (
|
24 | epsilonesque(v0.x * v1.y - v0.y * v1.x) &&
|
25 | epsilonesque(v0.y * v1.z - v0.z * v1.y) &&
|
26 | epsilonesque(v0.z * v1.x - v0.x * v1.z)
|
27 | );
|
28 | }
|
29 |
|
30 |
|
31 |
|
32 |
|
33 | function polygonDirection(polygon) {
|
34 | var sign, crossproduct, p0, p1, p2, v0, v1, i;
|
35 |
|
36 |
|
37 | p0 = polygon[polygon.length - 2];
|
38 | p1 = polygon[polygon.length - 1];
|
39 | p2 = polygon[0];
|
40 | v0 = vect(p0, p1);
|
41 | v1 = vect(p1, p2);
|
42 | crossproduct = calculateCrossproduct(v0, v1);
|
43 |
|
44 | sign = Math.sign(crossproduct);
|
45 |
|
46 |
|
47 | p0 = p1;
|
48 | p1 = p2;
|
49 | p2 = polygon[1];
|
50 | v0 = v1;
|
51 | v1 = vect(p1, p2);
|
52 | crossproduct = calculateCrossproduct(v0, v1);
|
53 |
|
54 | if (Math.sign(crossproduct) !== sign) {
|
55 | return undefined;
|
56 | }
|
57 |
|
58 |
|
59 | for (i = 2; i < polygon.length - 1; i++) {
|
60 | p0 = p1;
|
61 | p1 = p2;
|
62 | p2 = polygon[i];
|
63 | v0 = v1;
|
64 | v1 = vect(p1, p2);
|
65 | crossproduct = calculateCrossproduct(v0, v1);
|
66 |
|
67 | if (Math.sign(crossproduct) !== sign) {
|
68 | return undefined;
|
69 | }
|
70 | }
|
71 |
|
72 | return sign;
|
73 | }
|
74 |
|
75 | function vect(from, to) {
|
76 | return [to[0] - from[0], to[1] - from[1]];
|
77 | }
|
78 |
|
79 | function calculateCrossproduct(v0, v1) {
|
80 | return v0[0] * v1[1] - v0[1] * v1[0];
|
81 | }
|
82 |
|
83 |
|
84 |
|
85 | function ConflictListNode (face, vert) {
|
86 | this.face = face;
|
87 | this.vert = vert;
|
88 | this.nextf = null;
|
89 | this.prevf = null;
|
90 | this.nextv = null;
|
91 | this.prevv = null;
|
92 | }
|
93 |
|
94 |
|
95 | function ConflictList (forFace) {
|
96 | this.forFace = forFace;
|
97 | this.head = null;
|
98 | }
|
99 |
|
100 |
|
101 | ConflictList.prototype.add = function(cln) {
|
102 | if (this.head === null) {
|
103 | this.head = cln;
|
104 | } else {
|
105 | if (this.forFace) {
|
106 | this.head.prevv = cln;
|
107 | cln.nextv = this.head;
|
108 | this.head = cln;
|
109 | } else {
|
110 | this.head.prevf = cln;
|
111 | cln.nextf = this.head;
|
112 | this.head = cln;
|
113 | }
|
114 | }
|
115 | }
|
116 |
|
117 | ConflictList.prototype.isEmpty = function() {
|
118 | return this.head === null;
|
119 | }
|
120 |
|
121 |
|
122 | ConflictList.prototype.fill = function(visible) {
|
123 | if (this.forFace) {
|
124 | return;
|
125 | }
|
126 | var curr = this.head;
|
127 | do {
|
128 | visible.push(curr.face);
|
129 | curr.face.marked = true;
|
130 | curr = curr.nextf;
|
131 | } while (curr !== null);
|
132 | }
|
133 |
|
134 | ConflictList.prototype.removeAll = function() {
|
135 | if (this.forFace) {
|
136 | var curr = this.head;
|
137 | do {
|
138 | if (curr.prevf === null) {
|
139 | if (curr.nextf === null) {
|
140 | curr.vert.conflicts.head = null;
|
141 | } else {
|
142 | curr.nextf.prevf = null;
|
143 | curr.vert.conflicts.head = curr.nextf;
|
144 | }
|
145 | } else {
|
146 | if (curr.nextf != null) {
|
147 | curr.nextf.prevf = curr.prevf;
|
148 | }
|
149 | curr.prevf.nextf = curr.nextf;
|
150 | }
|
151 | curr = curr.nextv;
|
152 | if (curr != null) {
|
153 | curr.prevv = null;
|
154 | }
|
155 | } while (curr != null);
|
156 | } else {
|
157 | var curr = this.head;
|
158 | do {
|
159 | if (curr.prevv == null) {
|
160 | if (curr.nextv == null) {
|
161 | curr.face.conflicts.head = null;
|
162 | } else {
|
163 | curr.nextv.prevv = null;
|
164 | curr.face.conflicts.head = curr.nextv;
|
165 | }
|
166 | } else {
|
167 | if (curr.nextv != null) {
|
168 | curr.nextv.prevv = curr.prevv;
|
169 | }
|
170 | curr.prevv.nextv = curr.nextv;
|
171 | }
|
172 | curr = curr.nextf;
|
173 | if (curr != null)
|
174 | curr.prevf = null;
|
175 | } while (curr != null);
|
176 | }
|
177 | }
|
178 |
|
179 |
|
180 | ConflictList.prototype.getVertices = function() {
|
181 | var list = [],
|
182 | curr = this.head;
|
183 | while (curr !== null) {
|
184 | list.push(curr.vert);
|
185 | curr = curr.nextv;
|
186 | }
|
187 | return list;
|
188 | }
|
189 |
|
190 |
|
191 | function Vertex (x, y, z, weight, orig, isDummy) {
|
192 | this.x = x;
|
193 | this.y = y;
|
194 | this.weight = epsilon;
|
195 | this.index = 0;
|
196 | this.conflicts = new ConflictList(false);
|
197 | this.neighbours = null;
|
198 | this.nonClippedPolygon = null;
|
199 | this.polygon = null;
|
200 | this.originalObject = null;
|
201 | this.isDummy = false;
|
202 |
|
203 | if (orig !== undefined) {
|
204 | this.originalObject = orig;
|
205 | }
|
206 | if (isDummy != undefined) {
|
207 | this.isDummy = isDummy;
|
208 | }
|
209 | if (weight != null) {
|
210 | this.weight = weight;
|
211 | }
|
212 | if (z != null) {
|
213 | this.z = z;
|
214 | } else {
|
215 | this.z = this.projectZ(this.x, this.y, this.weight);
|
216 | }
|
217 | }
|
218 |
|
219 | Vertex.prototype.projectZ = function(x, y, weight) {
|
220 | return ((x*x) + (y*y) - weight);
|
221 | }
|
222 |
|
223 | Vertex.prototype.setWeight = function(weight) {
|
224 | this.weight = weight;
|
225 | this.z = this.projectZ(this.x, this.y, this.weight);
|
226 | }
|
227 |
|
228 | Vertex.prototype.subtract = function(v) {
|
229 | return new Vertex(v.x - this.x, v.y - this.y, v.z - this.z);
|
230 | }
|
231 |
|
232 | Vertex.prototype.crossproduct = function(v) {
|
233 | return new Vertex((this.y * v.z) - (this.z * v.y), (this.z * v.x) - (this.x * v.z), (this.x * v.y) - (this.y * v.x));
|
234 | }
|
235 |
|
236 | Vertex.prototype.equals = function(v) {
|
237 | return (this.x === v.x && this.y === v.y && this.z === v.z);
|
238 | }
|
239 |
|
240 |
|
241 |
|
242 |
|
243 | function Plane3D (face) {
|
244 | var p1 = face.verts[0];
|
245 | var p2 = face.verts[1];
|
246 | var p3 = face.verts[2];
|
247 | this.a = p1.y * (p2.z-p3.z) + p2.y * (p3.z-p1.z) + p3.y * (p1.z-p2.z);
|
248 | this.b = p1.z * (p2.x-p3.x) + p2.z * (p3.x-p1.x) + p3.z * (p1.x-p2.x);
|
249 | this.c = p1.x * (p2.y-p3.y) + p2.x * (p3.y-p1.y) + p3.x * (p1.y-p2.y);
|
250 | this.d = -1 * (p1.x * (p2.y*p3.z - p3.y*p2.z) + p2.x * (p3.y*p1.z - p1.y*p3.z) + p3.x * (p1.y*p2.z - p2.y*p1.z));
|
251 | }
|
252 |
|
253 | Plane3D.prototype.getNormZPlane = function() {
|
254 | return [
|
255 | -1 * (this.a / this.c),
|
256 | -1 * (this.b / this.c),
|
257 | -1 * (this.d / this.c)
|
258 | ];
|
259 | }
|
260 |
|
261 |
|
262 | Plane3D.prototype.getDualPointMappedToPlane = function() {
|
263 | var nplane = this.getNormZPlane();
|
264 | var dualPoint = new Point2D(nplane[0]/2, nplane[1]/2);
|
265 | return dualPoint;
|
266 | }
|
267 |
|
268 |
|
269 | function Point2D (x, y) {
|
270 | this.x = x;
|
271 | this.y = y;
|
272 | }
|
273 |
|
274 |
|
275 |
|
276 |
|
277 | function Vector (x, y, z) {
|
278 | this.x = x;
|
279 | this.y = y;
|
280 | this.z = z;
|
281 | }
|
282 |
|
283 | Vector.prototype.negate = function() {
|
284 | this.x *= -1;
|
285 | this.y *= -1;
|
286 | this.z *= -1;
|
287 | }
|
288 |
|
289 |
|
290 | Vector.prototype.normalize = function() {
|
291 | var lenght = Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z));
|
292 | if (lenght > 0) {
|
293 | this.x /= lenght;
|
294 | this.y /= lenght;
|
295 | this.z /= lenght;
|
296 | }
|
297 | }
|
298 |
|
299 |
|
300 |
|
301 |
|
302 | function HEdge (orig, dest, face) {
|
303 | this.next = null;
|
304 | this.prev = null;
|
305 | this.twin = null;
|
306 | this.orig = orig;
|
307 | this.dest = dest;
|
308 | this.iFace = face;
|
309 | }
|
310 |
|
311 | HEdge.prototype.isHorizon = function() {
|
312 | return this.twin !== null && !this.iFace.marked && this.twin.iFace.marked;
|
313 | }
|
314 |
|
315 |
|
316 | HEdge.prototype.findHorizon = function(horizon) {
|
317 | if (this.isHorizon()) {
|
318 | if (horizon.length > 0 && this === horizon[0]) {
|
319 | return;
|
320 | } else {
|
321 | horizon.push(this);
|
322 | this.next.findHorizon(horizon);
|
323 | }
|
324 | } else {
|
325 | if (this.twin !== null) {
|
326 | this.twin.next.findHorizon(horizon);
|
327 | }
|
328 | }
|
329 | }
|
330 |
|
331 |
|
332 | HEdge.prototype.isEqual = function(origin, dest) {
|
333 | return ((this.orig.equals(origin) && this.dest.equals(dest)) || (this.orig.equals(dest) && this.dest.equals(origin)));
|
334 | }
|
335 |
|
336 |
|
337 |
|
338 |
|
339 | function d3WeightedVoronoiError(message) {
|
340 | this.message = message;
|
341 | this.stack = new Error().stack;
|
342 | }
|
343 |
|
344 | d3WeightedVoronoiError.prototype.name = 'd3WeightedVoronoiError';
|
345 | d3WeightedVoronoiError.prototype = new Error();
|
346 |
|
347 |
|
348 | function Face(a, b, c, orient) {
|
349 | this.conflicts = new ConflictList(true);
|
350 | this.verts = [a, b, c];
|
351 | this.marked = false;
|
352 | var t = a.subtract(b).crossproduct(b.subtract(c));
|
353 |
|
354 | this.normal = new Vector(-t.x, -t.y, -t.z);
|
355 | this.normal.normalize();
|
356 | this.createEdges();
|
357 | this.dualPoint = null;
|
358 |
|
359 | if (orient != undefined) {
|
360 | this.orient(orient);
|
361 | }
|
362 | }
|
363 |
|
364 |
|
365 | Face.prototype.getDualPoint = function () {
|
366 | if (this.dualPoint == null) {
|
367 | var plane3d = new Plane3D(this);
|
368 | this.dualPoint = plane3d.getDualPointMappedToPlane();
|
369 | }
|
370 | return this.dualPoint;
|
371 | };
|
372 |
|
373 | Face.prototype.isVisibleFromBelow = function () {
|
374 | return this.normal.z < -1.4259414393190911e-9;
|
375 | };
|
376 |
|
377 | Face.prototype.createEdges = function () {
|
378 | this.edges = [];
|
379 | this.edges[0] = new HEdge(this.verts[0], this.verts[1], this);
|
380 | this.edges[1] = new HEdge(this.verts[1], this.verts[2], this);
|
381 | this.edges[2] = new HEdge(this.verts[2], this.verts[0], this);
|
382 | this.edges[0].next = this.edges[1];
|
383 | this.edges[0].prev = this.edges[2];
|
384 | this.edges[1].next = this.edges[2];
|
385 | this.edges[1].prev = this.edges[0];
|
386 | this.edges[2].next = this.edges[0];
|
387 | this.edges[2].prev = this.edges[1];
|
388 | };
|
389 |
|
390 |
|
391 | Face.prototype.orient = function (orient) {
|
392 | if (!(dot(this.normal, orient) < dot(this.normal, this.verts[0]))) {
|
393 | var temp = this.verts[1];
|
394 | this.verts[1] = this.verts[2];
|
395 | this.verts[2] = temp;
|
396 | this.normal.negate();
|
397 | this.createEdges();
|
398 | }
|
399 | };
|
400 |
|
401 |
|
402 | Face.prototype.getEdge = function (v0, v1) {
|
403 | for (var i = 0; i < 3; i++) {
|
404 | if (this.edges[i].isEqual(v0, v1)) {
|
405 | return this.edges[i];
|
406 | }
|
407 | }
|
408 | return null;
|
409 | };
|
410 |
|
411 |
|
412 | Face.prototype.link = function (face, v0, v1) {
|
413 | if (face instanceof Face) {
|
414 | var twin = face.getEdge(v0, v1);
|
415 | if (twin === null) {
|
416 | throw new d3WeightedVoronoiError('when linking, twin is null');
|
417 | }
|
418 | var edge = this.getEdge(v0, v1);
|
419 | if (edge === null) {
|
420 | throw new d3WeightedVoronoiError('when linking, twin is null');
|
421 | }
|
422 | twin.twin = edge;
|
423 | edge.twin = twin;
|
424 | } else {
|
425 | var twin = face;
|
426 | var edge = this.getEdge(twin.orig, twin.dest);
|
427 | twin.twin = edge;
|
428 | edge.twin = twin;
|
429 | }
|
430 | };
|
431 |
|
432 |
|
433 | Face.prototype.conflict = function (v) {
|
434 | return dot(this.normal, v) > dot(this.normal, this.verts[0]) + epsilon;
|
435 | };
|
436 |
|
437 | Face.prototype.getHorizon = function () {
|
438 | for (var i = 0; i < 3; i++) {
|
439 | if (this.edges[i].twin !== null && this.edges[i].twin.isHorizon()) {
|
440 | return this.edges[i];
|
441 | }
|
442 | }
|
443 | return null;
|
444 | };
|
445 |
|
446 | Face.prototype.removeConflict = function () {
|
447 | this.conflicts.removeAll();
|
448 | };
|
449 |
|
450 | function ConvexHull() {
|
451 | this.points = [];
|
452 | this.facets = [];
|
453 | this.created = [];
|
454 | this.horizon = [];
|
455 | this.visible = [];
|
456 | this.current = 0;
|
457 | }
|
458 |
|
459 |
|
460 | ConvexHull.prototype.init = function (boundingSites, sites) {
|
461 | this.points = [];
|
462 | for (var i = 0; i < sites.length; i++) {
|
463 | this.points[i] = new Vertex(sites[i].x, sites[i].y, sites[i].z, null, sites[i], false);
|
464 | }
|
465 | this.points = this.points.concat(boundingSites);
|
466 | };
|
467 |
|
468 | ConvexHull.prototype.permutate = function () {
|
469 | var pointSize = this.points.length;
|
470 | for (var i = pointSize - 1; i > 0; i--) {
|
471 | var ra = Math.floor(Math.random() * i);
|
472 | var temp = this.points[ra];
|
473 | temp.index = i;
|
474 | var currentItem = this.points[i];
|
475 | currentItem.index = ra;
|
476 | this.points.splice(ra, 1, currentItem);
|
477 | this.points.splice(i, 1, temp);
|
478 | }
|
479 | };
|
480 |
|
481 | (ConvexHull.prototype.prep = function () {
|
482 | if (this.points.length <= 3) {
|
483 | throw new d3WeightedVoronoiError('Less than 4 points');
|
484 | }
|
485 | for (var i = 0; i < this.points.length; i++) {
|
486 | this.points[i].index = i;
|
487 | }
|
488 |
|
489 | var v0, v1, v2, v3;
|
490 | var f1, f2, f3, f0;
|
491 | v0 = this.points[0];
|
492 | v1 = this.points[1];
|
493 | v2 = v3 = null;
|
494 |
|
495 |
|
496 | for (var i = 2; i < this.points.length; i++) {
|
497 | if (!(linearDependent(v0, this.points[i]) && linearDependent(v1, this.points[i]))) {
|
498 | v2 = this.points[i];
|
499 | v2.index = 2;
|
500 | this.points[2].index = i;
|
501 | this.points.splice(i, 1, this.points[2]);
|
502 | this.points.splice(2, 1, v2);
|
503 | break;
|
504 | }
|
505 | }
|
506 | if (v2 === null) {
|
507 | throw new d3WeightedVoronoiError('Not enough non-planar Points (v2 is null)');
|
508 | }
|
509 |
|
510 |
|
511 | f0 = new Face(v0, v1, v2);
|
512 |
|
513 | for (var i = 3; i < this.points.length; i++) {
|
514 | if (!epsilonesque(dot(f0.normal, f0.verts[0]) - dot(f0.normal, this.points[i]))) {
|
515 | v3 = this.points[i];
|
516 | v3.index = 3;
|
517 | this.points[3].index = i;
|
518 | this.points.splice(i, 1, this.points[3]);
|
519 | this.points.splice(3, 1, v3);
|
520 | break;
|
521 | }
|
522 | }
|
523 | if (v3 === null) {
|
524 | throw new d3WeightedVoronoiError('Not enough non-planar Points (v3 is null)');
|
525 | }
|
526 |
|
527 | f0.orient(v3);
|
528 | f1 = new Face(v0, v2, v3, v1);
|
529 | f2 = new Face(v0, v1, v3, v2);
|
530 | f3 = new Face(v1, v2, v3, v0);
|
531 | this.addFacet(f0);
|
532 | this.addFacet(f1);
|
533 | this.addFacet(f2);
|
534 | this.addFacet(f3);
|
535 |
|
536 | f0.link(f1, v0, v2);
|
537 | f0.link(f2, v0, v1);
|
538 | f0.link(f3, v1, v2);
|
539 | f1.link(f2, v0, v3);
|
540 | f1.link(f3, v2, v3);
|
541 | f2.link(f3, v3, v1);
|
542 | this.current = 4;
|
543 |
|
544 | var v;
|
545 | for (var i = this.current; i < this.points.length; i++) {
|
546 | v = this.points[i];
|
547 | if (f0.conflict(v)) {
|
548 | this.addConflict(f0, v);
|
549 | }
|
550 | if (f1.conflict(v)) {
|
551 | this.addConflict(f1, v);
|
552 | }
|
553 | if (f2.conflict(v)) {
|
554 | this.addConflict(f2, v);
|
555 | }
|
556 | if (f3.conflict(v)) {
|
557 | this.addConflict(f3, v);
|
558 | }
|
559 | }
|
560 | }),
|
561 |
|
562 | (ConvexHull.prototype.addConflicts = function (old1, old2, fn) {
|
563 | var l1 = old1.conflicts.getVertices();
|
564 | var l2 = old2.conflicts.getVertices();
|
565 | var nCL = [];
|
566 | var v1, v2;
|
567 | var i, l;
|
568 | i = l = 0;
|
569 |
|
570 | while (i < l1.length || l < l2.length) {
|
571 | if (i < l1.length && l < l2.length) {
|
572 | v1 = l1[i];
|
573 | v2 = l2[l];
|
574 |
|
575 | if (v1.index === v2.index) {
|
576 | nCL.push(v1);
|
577 | i++;
|
578 | l++;
|
579 | } else if (v1.index > v2.index) {
|
580 | nCL.push(v1);
|
581 | i++;
|
582 | } else {
|
583 | nCL.push(v2);
|
584 | l++;
|
585 | }
|
586 | } else if (i < l1.length) {
|
587 | nCL.push(l1[i++]);
|
588 | } else {
|
589 | nCL.push(l2[l++]);
|
590 | }
|
591 | }
|
592 |
|
593 | for (var i = nCL.length - 1; i >= 0; i--) {
|
594 | v1 = nCL[i];
|
595 | if (fn.conflict(v1)) this.addConflict(fn, v1);
|
596 | }
|
597 | });
|
598 |
|
599 |
|
600 | ConvexHull.prototype.addConflict = function (face, vert) {
|
601 | var e = new ConflictListNode(face, vert);
|
602 | face.conflicts.add(e);
|
603 | vert.conflicts.add(e);
|
604 | };
|
605 |
|
606 |
|
607 | ConvexHull.prototype.removeConflict = function (f) {
|
608 | f.removeConflict();
|
609 | var index = f.index;
|
610 | f.index = -1;
|
611 | if (index === this.facets.length - 1) {
|
612 | this.facets.splice(this.facets.length - 1, 1);
|
613 | return;
|
614 | }
|
615 | if (index >= this.facets.length || index < 0) return;
|
616 | var last = this.facets.splice(this.facets.length - 1, 1);
|
617 | last[0].index = index;
|
618 | this.facets.splice(index, 1, last[0]);
|
619 | };
|
620 |
|
621 |
|
622 | ConvexHull.prototype.addFacet = function (face) {
|
623 | face.index = this.facets.length;
|
624 | this.facets.push(face);
|
625 | };
|
626 |
|
627 | ConvexHull.prototype.compute = function () {
|
628 | this.prep();
|
629 | while (this.current < this.points.length) {
|
630 | var next = this.points[this.current];
|
631 | if (next.conflicts.isEmpty()) {
|
632 |
|
633 | this.current++;
|
634 | continue;
|
635 | }
|
636 | this.created = [];
|
637 | this.horizon = [];
|
638 | this.visible = [];
|
639 |
|
640 | next.conflicts.fill(this.visible);
|
641 |
|
642 | var e;
|
643 | for (var jF = 0; jF < this.visible.length; jF++) {
|
644 | e = this.visible[jF].getHorizon();
|
645 | if (e !== null) {
|
646 | e.findHorizon(this.horizon);
|
647 | break;
|
648 | }
|
649 | }
|
650 | var last = null,
|
651 | first = null;
|
652 |
|
653 | for (var hEi = 0; hEi < this.horizon.length; hEi++) {
|
654 | var hE = this.horizon[hEi];
|
655 | var fn = new Face(next, hE.orig, hE.dest, hE.twin.next.dest);
|
656 | fn.conflicts = new ConflictList(true);
|
657 |
|
658 | this.addFacet(fn);
|
659 | this.created.push(fn);
|
660 |
|
661 | this.addConflicts(hE.iFace, hE.twin.iFace, fn);
|
662 |
|
663 | fn.link(hE);
|
664 | if (last !== null) fn.link(last, next, hE.orig);
|
665 | last = fn;
|
666 | if (first === null) first = fn;
|
667 | }
|
668 |
|
669 | if (first !== null && last !== null) {
|
670 | last.link(first, next, this.horizon[0].orig);
|
671 | }
|
672 | if (this.created.length != 0) {
|
673 |
|
674 | for (var f = 0; f < this.visible.length; f++) {
|
675 | this.removeConflict(this.visible[f]);
|
676 | }
|
677 | this.current++;
|
678 | this.created = [];
|
679 | }
|
680 | }
|
681 | return this.facets;
|
682 | };
|
683 |
|
684 | ConvexHull.prototype.clear = function () {
|
685 | this.points = [];
|
686 | this.facets = [];
|
687 | this.created = [];
|
688 | this.horizon = [];
|
689 | this.visible = [];
|
690 | this.current = 0;
|
691 | };
|
692 |
|
693 | function polygonClip(clip, subject) {
|
694 |
|
695 |
|
696 |
|
697 |
|
698 |
|
699 |
|
700 |
|
701 | var input,
|
702 | closed = polygonClosed(subject),
|
703 | i = -1,
|
704 | n = clip.length - polygonClosed(clip),
|
705 | j,
|
706 | m,
|
707 | a = clip[n - 1],
|
708 | b,
|
709 | c,
|
710 | d,
|
711 | intersection;
|
712 |
|
713 | while (++i < n) {
|
714 | input = subject.slice();
|
715 | subject.length = 0;
|
716 | b = clip[i];
|
717 | c = input[(m = input.length - closed) - 1];
|
718 | j = -1;
|
719 | while (++j < m) {
|
720 | d = input[j];
|
721 | if (polygonInside(d, a, b)) {
|
722 | if (!polygonInside(c, a, b)) {
|
723 | intersection = polygonIntersect(c, d, a, b);
|
724 | if (isFinite(intersection[0])) {
|
725 | subject.push(intersection);
|
726 | }
|
727 | }
|
728 | subject.push(d);
|
729 | } else if (polygonInside(c, a, b)) {
|
730 | intersection = polygonIntersect(c, d, a, b);
|
731 | if (isFinite(intersection[0])) {
|
732 | subject.push(intersection);
|
733 | }
|
734 | }
|
735 | c = d;
|
736 | }
|
737 | if (closed) subject.push(subject[0]);
|
738 | a = b;
|
739 | }
|
740 |
|
741 | return subject;
|
742 | }
|
743 |
|
744 | function polygonInside(p, a, b) {
|
745 | return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]);
|
746 | }
|
747 |
|
748 |
|
749 |
|
750 | function polygonIntersect(c, d, a, b) {
|
751 | var x1 = c[0],
|
752 | x3 = a[0],
|
753 | x21 = d[0] - x1,
|
754 | x43 = b[0] - x3,
|
755 | y1 = c[1],
|
756 | y3 = a[1],
|
757 | y21 = d[1] - y1,
|
758 | y43 = b[1] - y3,
|
759 | ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21);
|
760 | return [x1 + ua * x21, y1 + ua * y21];
|
761 | }
|
762 |
|
763 |
|
764 | function polygonClosed(coordinates) {
|
765 | var a = coordinates[0],
|
766 | b = coordinates[coordinates.length - 1];
|
767 | return !(a[0] - b[0] || a[1] - b[1]);
|
768 | }
|
769 |
|
770 |
|
771 | function getFacesOfDestVertex(edge) {
|
772 | var faces = [];
|
773 | var previous = edge;
|
774 | var first = edge.dest;
|
775 | var site = first.originalObject;
|
776 | var neighbours = [];
|
777 | do {
|
778 | previous = previous.twin.prev;
|
779 | var siteOrigin = previous.orig.originalObject;
|
780 | if (!siteOrigin.isDummy) {
|
781 | neighbours.push(siteOrigin);
|
782 | }
|
783 | var iFace = previous.iFace;
|
784 | if (iFace.isVisibleFromBelow()) {
|
785 | faces.push(iFace);
|
786 | }
|
787 | } while (previous !== edge);
|
788 | site.neighbours = neighbours;
|
789 | return faces;
|
790 | }
|
791 |
|
792 |
|
793 |
|
794 |
|
795 | function computePowerDiagramIntegrated (sites, boundingSites, clippingPolygon) {
|
796 | var convexHull = new ConvexHull();
|
797 | convexHull.clear();
|
798 | convexHull.init(boundingSites, sites);
|
799 |
|
800 | var facets = convexHull.compute(sites);
|
801 | var polygons = [];
|
802 | var verticesVisited = [];
|
803 | var facetCount = facets.length;
|
804 |
|
805 | for (var i = 0; i < facetCount; i++) {
|
806 | var facet = facets[i];
|
807 | if (facet.isVisibleFromBelow()) {
|
808 | for (var e = 0; e < 3; e++) {
|
809 |
|
810 | var edge = facet.edges[e];
|
811 | var destVertex = edge.dest;
|
812 | var site = destVertex.originalObject;
|
813 |
|
814 | if (!verticesVisited[destVertex.index]) {
|
815 | verticesVisited[destVertex.index] = true;
|
816 | if (site.isDummy) {
|
817 |
|
818 | continue;
|
819 | }
|
820 |
|
821 | var faces = getFacesOfDestVertex(edge);
|
822 | var protopoly = [];
|
823 | var lastX = null;
|
824 | var lastY = null;
|
825 | var dx = 1;
|
826 | var dy = 1;
|
827 | for (var j = 0; j < faces.length; j++) {
|
828 | var point = faces[j].getDualPoint();
|
829 | var x1 = point.x;
|
830 | var y1 = point.y;
|
831 | if (lastX !== null) {
|
832 | dx = lastX - x1;
|
833 | dy = lastY - y1;
|
834 | if (dx < 0) {
|
835 | dx = -dx;
|
836 | }
|
837 | if (dy < 0) {
|
838 | dy = -dy;
|
839 | }
|
840 | }
|
841 | if (dx > epsilon || dy > epsilon) {
|
842 | protopoly.push([x1, y1]);
|
843 | lastX = x1;
|
844 | lastY = y1;
|
845 | }
|
846 | }
|
847 |
|
848 | site.nonClippedPolygon = protopoly.reverse();
|
849 | if (!site.isDummy && d3Polygon.polygonLength(site.nonClippedPolygon) > 0) {
|
850 | var clippedPoly = polygonClip(clippingPolygon, site.nonClippedPolygon);
|
851 | site.polygon = clippedPoly;
|
852 | clippedPoly.site = site;
|
853 | if (clippedPoly.length > 0) {
|
854 | polygons.push(clippedPoly);
|
855 | }
|
856 | }
|
857 | }
|
858 | }
|
859 | }
|
860 | }
|
861 | return polygons;
|
862 | }
|
863 |
|
864 | function weightedVoronoi() {
|
865 |
|
866 | var x = function (d) {
|
867 | return d.x;
|
868 | };
|
869 | var y = function (d) {
|
870 | return d.y;
|
871 | };
|
872 | var weight = function (d) {
|
873 | return d.weight;
|
874 | };
|
875 | var clip = [
|
876 | [0, 0],
|
877 | [0, 1],
|
878 | [1, 1],
|
879 | [1, 0],
|
880 | ];
|
881 | var extent = [
|
882 | [0, 0],
|
883 | [1, 1],
|
884 | ];
|
885 | var size = [1, 1];
|
886 |
|
887 |
|
888 |
|
889 |
|
890 |
|
891 | function _weightedVoronoi(data) {
|
892 | var formatedSites;
|
893 |
|
894 |
|
895 | formatedSites = data.map(function (d) {
|
896 | return new Vertex(x(d), y(d), null, weight(d), d, false);
|
897 | });
|
898 |
|
899 |
|
900 | return computePowerDiagramIntegrated(formatedSites, boundingSites(), clip);
|
901 | }
|
902 |
|
903 | _weightedVoronoi.x = function (_) {
|
904 | if (!arguments.length) {
|
905 | return x;
|
906 | }
|
907 |
|
908 | x = _;
|
909 | return _weightedVoronoi;
|
910 | };
|
911 |
|
912 | _weightedVoronoi.y = function (_) {
|
913 | if (!arguments.length) {
|
914 | return y;
|
915 | }
|
916 |
|
917 | y = _;
|
918 | return _weightedVoronoi;
|
919 | };
|
920 |
|
921 | _weightedVoronoi.weight = function (_) {
|
922 | if (!arguments.length) {
|
923 | return weight;
|
924 | }
|
925 |
|
926 | weight = _;
|
927 | return _weightedVoronoi;
|
928 | };
|
929 |
|
930 | _weightedVoronoi.clip = function (_) {
|
931 | var direction, xExtent, yExtent;
|
932 |
|
933 | if (!arguments.length) {
|
934 | return clip;
|
935 | }
|
936 |
|
937 | xExtent = d3Array.extent(
|
938 | _.map(function (c) {
|
939 | return c[0];
|
940 | })
|
941 | );
|
942 | yExtent = d3Array.extent(
|
943 | _.map(function (c) {
|
944 | return c[1];
|
945 | })
|
946 | );
|
947 | direction = polygonDirection(_);
|
948 | if (direction === undefined) {
|
949 | clip = d3Polygon.polygonHull(_);
|
950 | } else if (direction === 1) {
|
951 | clip = _.reverse();
|
952 | } else {
|
953 | clip = _;
|
954 | }
|
955 | extent = [
|
956 | [xExtent[0], yExtent[0]],
|
957 | [xExtent[1], yExtent[1]],
|
958 | ];
|
959 | size = [xExtent[1] - xExtent[0], yExtent[1] - yExtent[0]];
|
960 | return _weightedVoronoi;
|
961 | };
|
962 |
|
963 | _weightedVoronoi.extent = function (_) {
|
964 | if (!arguments.length) {
|
965 | return extent;
|
966 | }
|
967 |
|
968 | clip = [_[0], [_[0][0], _[1][1]], _[1], [_[1][0], _[0][1]]];
|
969 | extent = _;
|
970 | size = [_[1][0] - _[0][0], _[1][1] - _[0][1]];
|
971 | return _weightedVoronoi;
|
972 | };
|
973 |
|
974 | _weightedVoronoi.size = function (_) {
|
975 | if (!arguments.length) {
|
976 | return size;
|
977 | }
|
978 |
|
979 | clip = [
|
980 | [0, 0],
|
981 | [0, _[1]],
|
982 | [_[0], _[1]],
|
983 | [_[0], 0],
|
984 | ];
|
985 | extent = [[0, 0], _];
|
986 | size = _;
|
987 | return _weightedVoronoi;
|
988 | };
|
989 |
|
990 |
|
991 |
|
992 |
|
993 |
|
994 | function boundingSites() {
|
995 | var minX,
|
996 | maxX,
|
997 | minY,
|
998 | maxY,
|
999 | width,
|
1000 | height,
|
1001 | x0,
|
1002 | x1,
|
1003 | y0,
|
1004 | y1,
|
1005 | boundingData = [],
|
1006 | boundingSites = [];
|
1007 |
|
1008 | minX = extent[0][0];
|
1009 | maxX = extent[1][0];
|
1010 | minY = extent[0][1];
|
1011 | maxY = extent[1][1];
|
1012 | width = maxX - minX;
|
1013 | height = maxY - minY;
|
1014 | x0 = minX - width;
|
1015 | x1 = maxX + width;
|
1016 | y0 = minY - height;
|
1017 | y1 = maxY + height;
|
1018 |
|
1019 |
|
1020 |
|
1021 |
|
1022 | boundingData[0] = [x0, y0];
|
1023 | boundingData[1] = [x0, y1];
|
1024 | boundingData[2] = [x1, y1];
|
1025 | boundingData[3] = [x1, y0];
|
1026 |
|
1027 | for (var i = 0; i < 4; i++) {
|
1028 | boundingSites.push(
|
1029 | new Vertex(
|
1030 | boundingData[i][0],
|
1031 | boundingData[i][1],
|
1032 | null,
|
1033 | epsilon,
|
1034 | new Vertex(boundingData[i][0], boundingData[i][1], null, epsilon, null, true),
|
1035 | true
|
1036 | )
|
1037 | );
|
1038 | }
|
1039 |
|
1040 | return boundingSites;
|
1041 | }
|
1042 |
|
1043 | return _weightedVoronoi;
|
1044 | }
|
1045 |
|
1046 | exports.weightedVoronoi = weightedVoronoi;
|
1047 | exports.d3WeightedVoronoiError = d3WeightedVoronoiError;
|
1048 |
|
1049 | Object.defineProperty(exports, '__esModule', { value: true });
|
1050 |
|
1051 | })); |
\ | No newline at end of file |