-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathvoronoi.js
124 lines (110 loc) · 2.98 KB
/
voronoi.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import {
geoCentroid as centroid,
geoGnomonic as gnomonic,
geoDistance
} from "d3-geo";
import { degrees } from "../math.js";
import polyhedral from "./index.js";
// it is possible to pass a specific projection on each face
// by default is is a gnomonic projection centered on the face's centroid
// scale 1 by convention
const faceProjection0 = (face) => gnomonic()
.scale(1)
.translate([0, 0])
.rotate([
Math.abs(face.site[1]) > 89.99999999 ? 0 : -face.site[0],
-face.site[1]
]);
export default function(
parents = [],
polygons = { features: [] },
faceProjection = faceProjection0,
find
) {
if (find === undefined) find = find0;
let faces = [];
function build_tree() {
// the faces from the polyhedron each yield
// - face: its vertices
// - site: its voronoi site (default: centroid)
// - project: local projection on this face
faces = polygons.features.map((feature, i) => {
const polygon = feature.geometry.coordinates[0];
const face = polygon.slice(0, -1);
face.site =
feature.properties && feature.properties.sitecoordinates
? feature.properties.sitecoordinates
: centroid(feature.geometry);
return {
face,
site: face.site,
id: i,
project: faceProjection(face)
};
});
// Build a tree of the faces, starting with face 0 (North Pole)
// which has no parent (-1)
parents.forEach((d, i) => {
const node = faces[d];
node && (node.children || (node.children = [])).push(faces[i]);
});
}
// a basic function to find the polygon that contains the point
function find0(lambda, phi) {
let d0 = Infinity;
let found = -1;
for (let i = 0; i < faces.length; i++) {
const d = geoDistance(faces[i].site, [lambda, phi]);
if (d < d0) {
d0 = d;
found = i;
}
}
return found;
}
function faceFind(lambda, phi) {
return faces[find(lambda * degrees, phi * degrees)];
}
let p = gnomonic();
function reset() {
let rotate = p.rotate(),
translate = p.translate(),
center = p.center(),
scale = p.scale(),
angle = p.angle();
if (faces.length) {
p = polyhedral(faces.find((face, i) => face && !faces[parents[i]]), faceFind);
}
p.parents = function(_) {
if (!arguments.length) return parents;
parents = _;
build_tree();
return reset();
};
p.polygons = function(_) {
if (!arguments.length) return polygons;
polygons = _;
build_tree();
return reset();
};
p.faceProjection = function(_) {
if (!arguments.length) return faceProjection;
faceProjection = _;
build_tree();
return reset();
};
p.faceFind = function(_) {
if (!arguments.length) return find;
find = _;
return reset();
};
return p
.rotate(rotate)
.translate(translate)
.center(center)
.scale(scale)
.angle(angle);
}
build_tree();
return reset();
}