Daniel@0
|
1 !function() {
|
Daniel@0
|
2 var topojson = {
|
Daniel@0
|
3 version: "1.6.19",
|
Daniel@0
|
4 mesh: function(topology) { return object(topology, meshArcs.apply(this, arguments)); },
|
Daniel@0
|
5 meshArcs: meshArcs,
|
Daniel@0
|
6 merge: function(topology) { return object(topology, mergeArcs.apply(this, arguments)); },
|
Daniel@0
|
7 mergeArcs: mergeArcs,
|
Daniel@0
|
8 feature: featureOrCollection,
|
Daniel@0
|
9 neighbors: neighbors,
|
Daniel@0
|
10 presimplify: presimplify
|
Daniel@0
|
11 };
|
Daniel@0
|
12
|
Daniel@0
|
13 function stitchArcs(topology, arcs) {
|
Daniel@0
|
14 var stitchedArcs = {},
|
Daniel@0
|
15 fragmentByStart = {},
|
Daniel@0
|
16 fragmentByEnd = {},
|
Daniel@0
|
17 fragments = [],
|
Daniel@0
|
18 emptyIndex = -1;
|
Daniel@0
|
19
|
Daniel@0
|
20 // Stitch empty arcs first, since they may be subsumed by other arcs.
|
Daniel@0
|
21 arcs.forEach(function(i, j) {
|
Daniel@0
|
22 var arc = topology.arcs[i < 0 ? ~i : i], t;
|
Daniel@0
|
23 if (arc.length < 3 && !arc[1][0] && !arc[1][1]) {
|
Daniel@0
|
24 t = arcs[++emptyIndex], arcs[emptyIndex] = i, arcs[j] = t;
|
Daniel@0
|
25 }
|
Daniel@0
|
26 });
|
Daniel@0
|
27
|
Daniel@0
|
28 arcs.forEach(function(i) {
|
Daniel@0
|
29 var e = ends(i),
|
Daniel@0
|
30 start = e[0],
|
Daniel@0
|
31 end = e[1],
|
Daniel@0
|
32 f, g;
|
Daniel@0
|
33
|
Daniel@0
|
34 if (f = fragmentByEnd[start]) {
|
Daniel@0
|
35 delete fragmentByEnd[f.end];
|
Daniel@0
|
36 f.push(i);
|
Daniel@0
|
37 f.end = end;
|
Daniel@0
|
38 if (g = fragmentByStart[end]) {
|
Daniel@0
|
39 delete fragmentByStart[g.start];
|
Daniel@0
|
40 var fg = g === f ? f : f.concat(g);
|
Daniel@0
|
41 fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.end] = fg;
|
Daniel@0
|
42 } else {
|
Daniel@0
|
43 fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
|
Daniel@0
|
44 }
|
Daniel@0
|
45 } else if (f = fragmentByStart[end]) {
|
Daniel@0
|
46 delete fragmentByStart[f.start];
|
Daniel@0
|
47 f.unshift(i);
|
Daniel@0
|
48 f.start = start;
|
Daniel@0
|
49 if (g = fragmentByEnd[start]) {
|
Daniel@0
|
50 delete fragmentByEnd[g.end];
|
Daniel@0
|
51 var gf = g === f ? f : g.concat(f);
|
Daniel@0
|
52 fragmentByStart[gf.start = g.start] = fragmentByEnd[gf.end = f.end] = gf;
|
Daniel@0
|
53 } else {
|
Daniel@0
|
54 fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
|
Daniel@0
|
55 }
|
Daniel@0
|
56 } else {
|
Daniel@0
|
57 f = [i];
|
Daniel@0
|
58 fragmentByStart[f.start = start] = fragmentByEnd[f.end = end] = f;
|
Daniel@0
|
59 }
|
Daniel@0
|
60 });
|
Daniel@0
|
61
|
Daniel@0
|
62 function ends(i) {
|
Daniel@0
|
63 var arc = topology.arcs[i < 0 ? ~i : i], p0 = arc[0], p1;
|
Daniel@0
|
64 if (topology.transform) p1 = [0, 0], arc.forEach(function(dp) { p1[0] += dp[0], p1[1] += dp[1]; });
|
Daniel@0
|
65 else p1 = arc[arc.length - 1];
|
Daniel@0
|
66 return i < 0 ? [p1, p0] : [p0, p1];
|
Daniel@0
|
67 }
|
Daniel@0
|
68
|
Daniel@0
|
69 function flush(fragmentByEnd, fragmentByStart) {
|
Daniel@0
|
70 for (var k in fragmentByEnd) {
|
Daniel@0
|
71 var f = fragmentByEnd[k];
|
Daniel@0
|
72 delete fragmentByStart[f.start];
|
Daniel@0
|
73 delete f.start;
|
Daniel@0
|
74 delete f.end;
|
Daniel@0
|
75 f.forEach(function(i) { stitchedArcs[i < 0 ? ~i : i] = 1; });
|
Daniel@0
|
76 fragments.push(f);
|
Daniel@0
|
77 }
|
Daniel@0
|
78 }
|
Daniel@0
|
79
|
Daniel@0
|
80 flush(fragmentByEnd, fragmentByStart);
|
Daniel@0
|
81 flush(fragmentByStart, fragmentByEnd);
|
Daniel@0
|
82 arcs.forEach(function(i) { if (!stitchedArcs[i < 0 ? ~i : i]) fragments.push([i]); });
|
Daniel@0
|
83
|
Daniel@0
|
84 return fragments;
|
Daniel@0
|
85 }
|
Daniel@0
|
86
|
Daniel@0
|
87 function meshArcs(topology, o, filter) {
|
Daniel@0
|
88 var arcs = [];
|
Daniel@0
|
89
|
Daniel@0
|
90 if (arguments.length > 1) {
|
Daniel@0
|
91 var geomsByArc = [],
|
Daniel@0
|
92 geom;
|
Daniel@0
|
93
|
Daniel@0
|
94 function arc(i) {
|
Daniel@0
|
95 var j = i < 0 ? ~i : i;
|
Daniel@0
|
96 (geomsByArc[j] || (geomsByArc[j] = [])).push({i: i, g: geom});
|
Daniel@0
|
97 }
|
Daniel@0
|
98
|
Daniel@0
|
99 function line(arcs) {
|
Daniel@0
|
100 arcs.forEach(arc);
|
Daniel@0
|
101 }
|
Daniel@0
|
102
|
Daniel@0
|
103 function polygon(arcs) {
|
Daniel@0
|
104 arcs.forEach(line);
|
Daniel@0
|
105 }
|
Daniel@0
|
106
|
Daniel@0
|
107 function geometry(o) {
|
Daniel@0
|
108 if (o.type === "GeometryCollection") o.geometries.forEach(geometry);
|
Daniel@0
|
109 else if (o.type in geometryType) geom = o, geometryType[o.type](o.arcs);
|
Daniel@0
|
110 }
|
Daniel@0
|
111
|
Daniel@0
|
112 var geometryType = {
|
Daniel@0
|
113 LineString: line,
|
Daniel@0
|
114 MultiLineString: polygon,
|
Daniel@0
|
115 Polygon: polygon,
|
Daniel@0
|
116 MultiPolygon: function(arcs) { arcs.forEach(polygon); }
|
Daniel@0
|
117 };
|
Daniel@0
|
118
|
Daniel@0
|
119 geometry(o);
|
Daniel@0
|
120
|
Daniel@0
|
121 geomsByArc.forEach(arguments.length < 3
|
Daniel@0
|
122 ? function(geoms) { arcs.push(geoms[0].i); }
|
Daniel@0
|
123 : function(geoms) { if (filter(geoms[0].g, geoms[geoms.length - 1].g)) arcs.push(geoms[0].i); });
|
Daniel@0
|
124 } else {
|
Daniel@0
|
125 for (var i = 0, n = topology.arcs.length; i < n; ++i) arcs.push(i);
|
Daniel@0
|
126 }
|
Daniel@0
|
127
|
Daniel@0
|
128 return {type: "MultiLineString", arcs: stitchArcs(topology, arcs)};
|
Daniel@0
|
129 }
|
Daniel@0
|
130
|
Daniel@0
|
131 function mergeArcs(topology, objects) {
|
Daniel@0
|
132 var polygonsByArc = {},
|
Daniel@0
|
133 polygons = [],
|
Daniel@0
|
134 components = [];
|
Daniel@0
|
135
|
Daniel@0
|
136 objects.forEach(function(o) {
|
Daniel@0
|
137 if (o.type === "Polygon") register(o.arcs);
|
Daniel@0
|
138 else if (o.type === "MultiPolygon") o.arcs.forEach(register);
|
Daniel@0
|
139 });
|
Daniel@0
|
140
|
Daniel@0
|
141 function register(polygon) {
|
Daniel@0
|
142 polygon.forEach(function(ring) {
|
Daniel@0
|
143 ring.forEach(function(arc) {
|
Daniel@0
|
144 (polygonsByArc[arc = arc < 0 ? ~arc : arc] || (polygonsByArc[arc] = [])).push(polygon);
|
Daniel@0
|
145 });
|
Daniel@0
|
146 });
|
Daniel@0
|
147 polygons.push(polygon);
|
Daniel@0
|
148 }
|
Daniel@0
|
149
|
Daniel@0
|
150 function exterior(ring) {
|
Daniel@0
|
151 return cartesianRingArea(object(topology, {type: "Polygon", arcs: [ring]}).coordinates[0]) > 0; // TODO allow spherical?
|
Daniel@0
|
152 }
|
Daniel@0
|
153
|
Daniel@0
|
154 polygons.forEach(function(polygon) {
|
Daniel@0
|
155 if (!polygon._) {
|
Daniel@0
|
156 var component = [],
|
Daniel@0
|
157 neighbors = [polygon];
|
Daniel@0
|
158 polygon._ = 1;
|
Daniel@0
|
159 components.push(component);
|
Daniel@0
|
160 while (polygon = neighbors.pop()) {
|
Daniel@0
|
161 component.push(polygon);
|
Daniel@0
|
162 polygon.forEach(function(ring) {
|
Daniel@0
|
163 ring.forEach(function(arc) {
|
Daniel@0
|
164 polygonsByArc[arc < 0 ? ~arc : arc].forEach(function(polygon) {
|
Daniel@0
|
165 if (!polygon._) {
|
Daniel@0
|
166 polygon._ = 1;
|
Daniel@0
|
167 neighbors.push(polygon);
|
Daniel@0
|
168 }
|
Daniel@0
|
169 });
|
Daniel@0
|
170 });
|
Daniel@0
|
171 });
|
Daniel@0
|
172 }
|
Daniel@0
|
173 }
|
Daniel@0
|
174 });
|
Daniel@0
|
175
|
Daniel@0
|
176 polygons.forEach(function(polygon) {
|
Daniel@0
|
177 delete polygon._;
|
Daniel@0
|
178 });
|
Daniel@0
|
179
|
Daniel@0
|
180 return {
|
Daniel@0
|
181 type: "MultiPolygon",
|
Daniel@0
|
182 arcs: components.map(function(polygons) {
|
Daniel@0
|
183 var arcs = [];
|
Daniel@0
|
184
|
Daniel@0
|
185 // Extract the exterior (unique) arcs.
|
Daniel@0
|
186 polygons.forEach(function(polygon) {
|
Daniel@0
|
187 polygon.forEach(function(ring) {
|
Daniel@0
|
188 ring.forEach(function(arc) {
|
Daniel@0
|
189 if (polygonsByArc[arc < 0 ? ~arc : arc].length < 2) {
|
Daniel@0
|
190 arcs.push(arc);
|
Daniel@0
|
191 }
|
Daniel@0
|
192 });
|
Daniel@0
|
193 });
|
Daniel@0
|
194 });
|
Daniel@0
|
195
|
Daniel@0
|
196 // Stitch the arcs into one or more rings.
|
Daniel@0
|
197 arcs = stitchArcs(topology, arcs);
|
Daniel@0
|
198
|
Daniel@0
|
199 // If more than one ring is returned,
|
Daniel@0
|
200 // at most one of these rings can be the exterior;
|
Daniel@0
|
201 // this exterior ring has the same winding order
|
Daniel@0
|
202 // as any exterior ring in the original polygons.
|
Daniel@0
|
203 if ((n = arcs.length) > 1) {
|
Daniel@0
|
204 var sgn = exterior(polygons[0][0]);
|
Daniel@0
|
205 for (var i = 0, t; i < n; ++i) {
|
Daniel@0
|
206 if (sgn === exterior(arcs[i])) {
|
Daniel@0
|
207 t = arcs[0], arcs[0] = arcs[i], arcs[i] = t;
|
Daniel@0
|
208 break;
|
Daniel@0
|
209 }
|
Daniel@0
|
210 }
|
Daniel@0
|
211 }
|
Daniel@0
|
212
|
Daniel@0
|
213 return arcs;
|
Daniel@0
|
214 })
|
Daniel@0
|
215 };
|
Daniel@0
|
216 }
|
Daniel@0
|
217
|
Daniel@0
|
218 function featureOrCollection(topology, o) {
|
Daniel@0
|
219 return o.type === "GeometryCollection" ? {
|
Daniel@0
|
220 type: "FeatureCollection",
|
Daniel@0
|
221 features: o.geometries.map(function(o) { return feature(topology, o); })
|
Daniel@0
|
222 } : feature(topology, o);
|
Daniel@0
|
223 }
|
Daniel@0
|
224
|
Daniel@0
|
225 function feature(topology, o) {
|
Daniel@0
|
226 var f = {
|
Daniel@0
|
227 type: "Feature",
|
Daniel@0
|
228 id: o.id,
|
Daniel@0
|
229 properties: o.properties || {},
|
Daniel@0
|
230 geometry: object(topology, o)
|
Daniel@0
|
231 };
|
Daniel@0
|
232 if (o.id == null) delete f.id;
|
Daniel@0
|
233 return f;
|
Daniel@0
|
234 }
|
Daniel@0
|
235
|
Daniel@0
|
236 function object(topology, o) {
|
Daniel@0
|
237 var absolute = transformAbsolute(topology.transform),
|
Daniel@0
|
238 arcs = topology.arcs;
|
Daniel@0
|
239
|
Daniel@0
|
240 function arc(i, points) {
|
Daniel@0
|
241 if (points.length) points.pop();
|
Daniel@0
|
242 for (var a = arcs[i < 0 ? ~i : i], k = 0, n = a.length, p; k < n; ++k) {
|
Daniel@0
|
243 points.push(p = a[k].slice());
|
Daniel@0
|
244 absolute(p, k);
|
Daniel@0
|
245 }
|
Daniel@0
|
246 if (i < 0) reverse(points, n);
|
Daniel@0
|
247 }
|
Daniel@0
|
248
|
Daniel@0
|
249 function point(p) {
|
Daniel@0
|
250 p = p.slice();
|
Daniel@0
|
251 absolute(p, 0);
|
Daniel@0
|
252 return p;
|
Daniel@0
|
253 }
|
Daniel@0
|
254
|
Daniel@0
|
255 function line(arcs) {
|
Daniel@0
|
256 var points = [];
|
Daniel@0
|
257 for (var i = 0, n = arcs.length; i < n; ++i) arc(arcs[i], points);
|
Daniel@0
|
258 if (points.length < 2) points.push(points[0].slice());
|
Daniel@0
|
259 return points;
|
Daniel@0
|
260 }
|
Daniel@0
|
261
|
Daniel@0
|
262 function ring(arcs) {
|
Daniel@0
|
263 var points = line(arcs);
|
Daniel@0
|
264 while (points.length < 4) points.push(points[0].slice());
|
Daniel@0
|
265 return points;
|
Daniel@0
|
266 }
|
Daniel@0
|
267
|
Daniel@0
|
268 function polygon(arcs) {
|
Daniel@0
|
269 return arcs.map(ring);
|
Daniel@0
|
270 }
|
Daniel@0
|
271
|
Daniel@0
|
272 function geometry(o) {
|
Daniel@0
|
273 var t = o.type;
|
Daniel@0
|
274 return t === "GeometryCollection" ? {type: t, geometries: o.geometries.map(geometry)}
|
Daniel@0
|
275 : t in geometryType ? {type: t, coordinates: geometryType[t](o)}
|
Daniel@0
|
276 : null;
|
Daniel@0
|
277 }
|
Daniel@0
|
278
|
Daniel@0
|
279 var geometryType = {
|
Daniel@0
|
280 Point: function(o) { return point(o.coordinates); },
|
Daniel@0
|
281 MultiPoint: function(o) { return o.coordinates.map(point); },
|
Daniel@0
|
282 LineString: function(o) { return line(o.arcs); },
|
Daniel@0
|
283 MultiLineString: function(o) { return o.arcs.map(line); },
|
Daniel@0
|
284 Polygon: function(o) { return polygon(o.arcs); },
|
Daniel@0
|
285 MultiPolygon: function(o) { return o.arcs.map(polygon); }
|
Daniel@0
|
286 };
|
Daniel@0
|
287
|
Daniel@0
|
288 return geometry(o);
|
Daniel@0
|
289 }
|
Daniel@0
|
290
|
Daniel@0
|
291 function reverse(array, n) {
|
Daniel@0
|
292 var t, j = array.length, i = j - n; while (i < --j) t = array[i], array[i++] = array[j], array[j] = t;
|
Daniel@0
|
293 }
|
Daniel@0
|
294
|
Daniel@0
|
295 function bisect(a, x) {
|
Daniel@0
|
296 var lo = 0, hi = a.length;
|
Daniel@0
|
297 while (lo < hi) {
|
Daniel@0
|
298 var mid = lo + hi >>> 1;
|
Daniel@0
|
299 if (a[mid] < x) lo = mid + 1;
|
Daniel@0
|
300 else hi = mid;
|
Daniel@0
|
301 }
|
Daniel@0
|
302 return lo;
|
Daniel@0
|
303 }
|
Daniel@0
|
304
|
Daniel@0
|
305 function neighbors(objects) {
|
Daniel@0
|
306 var indexesByArc = {}, // arc index -> array of object indexes
|
Daniel@0
|
307 neighbors = objects.map(function() { return []; });
|
Daniel@0
|
308
|
Daniel@0
|
309 function line(arcs, i) {
|
Daniel@0
|
310 arcs.forEach(function(a) {
|
Daniel@0
|
311 if (a < 0) a = ~a;
|
Daniel@0
|
312 var o = indexesByArc[a];
|
Daniel@0
|
313 if (o) o.push(i);
|
Daniel@0
|
314 else indexesByArc[a] = [i];
|
Daniel@0
|
315 });
|
Daniel@0
|
316 }
|
Daniel@0
|
317
|
Daniel@0
|
318 function polygon(arcs, i) {
|
Daniel@0
|
319 arcs.forEach(function(arc) { line(arc, i); });
|
Daniel@0
|
320 }
|
Daniel@0
|
321
|
Daniel@0
|
322 function geometry(o, i) {
|
Daniel@0
|
323 if (o.type === "GeometryCollection") o.geometries.forEach(function(o) { geometry(o, i); });
|
Daniel@0
|
324 else if (o.type in geometryType) geometryType[o.type](o.arcs, i);
|
Daniel@0
|
325 }
|
Daniel@0
|
326
|
Daniel@0
|
327 var geometryType = {
|
Daniel@0
|
328 LineString: line,
|
Daniel@0
|
329 MultiLineString: polygon,
|
Daniel@0
|
330 Polygon: polygon,
|
Daniel@0
|
331 MultiPolygon: function(arcs, i) { arcs.forEach(function(arc) { polygon(arc, i); }); }
|
Daniel@0
|
332 };
|
Daniel@0
|
333
|
Daniel@0
|
334 objects.forEach(geometry);
|
Daniel@0
|
335
|
Daniel@0
|
336 for (var i in indexesByArc) {
|
Daniel@0
|
337 for (var indexes = indexesByArc[i], m = indexes.length, j = 0; j < m; ++j) {
|
Daniel@0
|
338 for (var k = j + 1; k < m; ++k) {
|
Daniel@0
|
339 var ij = indexes[j], ik = indexes[k], n;
|
Daniel@0
|
340 if ((n = neighbors[ij])[i = bisect(n, ik)] !== ik) n.splice(i, 0, ik);
|
Daniel@0
|
341 if ((n = neighbors[ik])[i = bisect(n, ij)] !== ij) n.splice(i, 0, ij);
|
Daniel@0
|
342 }
|
Daniel@0
|
343 }
|
Daniel@0
|
344 }
|
Daniel@0
|
345
|
Daniel@0
|
346 return neighbors;
|
Daniel@0
|
347 }
|
Daniel@0
|
348
|
Daniel@0
|
349 function presimplify(topology, triangleArea) {
|
Daniel@0
|
350 var absolute = transformAbsolute(topology.transform),
|
Daniel@0
|
351 relative = transformRelative(topology.transform),
|
Daniel@0
|
352 heap = minAreaHeap();
|
Daniel@0
|
353
|
Daniel@0
|
354 if (!triangleArea) triangleArea = cartesianTriangleArea;
|
Daniel@0
|
355
|
Daniel@0
|
356 topology.arcs.forEach(function(arc) {
|
Daniel@0
|
357 var triangles = [],
|
Daniel@0
|
358 maxArea = 0,
|
Daniel@0
|
359 triangle;
|
Daniel@0
|
360
|
Daniel@0
|
361 // To store each point’s effective area, we create a new array rather than
|
Daniel@0
|
362 // extending the passed-in point to workaround a Chrome/V8 bug (getting
|
Daniel@0
|
363 // stuck in smi mode). For midpoints, the initial effective area of
|
Daniel@0
|
364 // Infinity will be computed in the next step.
|
Daniel@0
|
365 for (var i = 0, n = arc.length, p; i < n; ++i) {
|
Daniel@0
|
366 p = arc[i];
|
Daniel@0
|
367 absolute(arc[i] = [p[0], p[1], Infinity], i);
|
Daniel@0
|
368 }
|
Daniel@0
|
369
|
Daniel@0
|
370 for (var i = 1, n = arc.length - 1; i < n; ++i) {
|
Daniel@0
|
371 triangle = arc.slice(i - 1, i + 2);
|
Daniel@0
|
372 triangle[1][2] = triangleArea(triangle);
|
Daniel@0
|
373 triangles.push(triangle);
|
Daniel@0
|
374 heap.push(triangle);
|
Daniel@0
|
375 }
|
Daniel@0
|
376
|
Daniel@0
|
377 for (var i = 0, n = triangles.length; i < n; ++i) {
|
Daniel@0
|
378 triangle = triangles[i];
|
Daniel@0
|
379 triangle.previous = triangles[i - 1];
|
Daniel@0
|
380 triangle.next = triangles[i + 1];
|
Daniel@0
|
381 }
|
Daniel@0
|
382
|
Daniel@0
|
383 while (triangle = heap.pop()) {
|
Daniel@0
|
384 var previous = triangle.previous,
|
Daniel@0
|
385 next = triangle.next;
|
Daniel@0
|
386
|
Daniel@0
|
387 // If the area of the current point is less than that of the previous point
|
Daniel@0
|
388 // to be eliminated, use the latter's area instead. This ensures that the
|
Daniel@0
|
389 // current point cannot be eliminated without eliminating previously-
|
Daniel@0
|
390 // eliminated points.
|
Daniel@0
|
391 if (triangle[1][2] < maxArea) triangle[1][2] = maxArea;
|
Daniel@0
|
392 else maxArea = triangle[1][2];
|
Daniel@0
|
393
|
Daniel@0
|
394 if (previous) {
|
Daniel@0
|
395 previous.next = next;
|
Daniel@0
|
396 previous[2] = triangle[2];
|
Daniel@0
|
397 update(previous);
|
Daniel@0
|
398 }
|
Daniel@0
|
399
|
Daniel@0
|
400 if (next) {
|
Daniel@0
|
401 next.previous = previous;
|
Daniel@0
|
402 next[0] = triangle[0];
|
Daniel@0
|
403 update(next);
|
Daniel@0
|
404 }
|
Daniel@0
|
405 }
|
Daniel@0
|
406
|
Daniel@0
|
407 arc.forEach(relative);
|
Daniel@0
|
408 });
|
Daniel@0
|
409
|
Daniel@0
|
410 function update(triangle) {
|
Daniel@0
|
411 heap.remove(triangle);
|
Daniel@0
|
412 triangle[1][2] = triangleArea(triangle);
|
Daniel@0
|
413 heap.push(triangle);
|
Daniel@0
|
414 }
|
Daniel@0
|
415
|
Daniel@0
|
416 return topology;
|
Daniel@0
|
417 };
|
Daniel@0
|
418
|
Daniel@0
|
419 function cartesianRingArea(ring) {
|
Daniel@0
|
420 var i = -1,
|
Daniel@0
|
421 n = ring.length,
|
Daniel@0
|
422 a,
|
Daniel@0
|
423 b = ring[n - 1],
|
Daniel@0
|
424 area = 0;
|
Daniel@0
|
425
|
Daniel@0
|
426 while (++i < n) {
|
Daniel@0
|
427 a = b;
|
Daniel@0
|
428 b = ring[i];
|
Daniel@0
|
429 area += a[0] * b[1] - a[1] * b[0];
|
Daniel@0
|
430 }
|
Daniel@0
|
431
|
Daniel@0
|
432 return area * .5;
|
Daniel@0
|
433 }
|
Daniel@0
|
434
|
Daniel@0
|
435 function cartesianTriangleArea(triangle) {
|
Daniel@0
|
436 var a = triangle[0], b = triangle[1], c = triangle[2];
|
Daniel@0
|
437 return Math.abs((a[0] - c[0]) * (b[1] - a[1]) - (a[0] - b[0]) * (c[1] - a[1]));
|
Daniel@0
|
438 }
|
Daniel@0
|
439
|
Daniel@0
|
440 function compareArea(a, b) {
|
Daniel@0
|
441 return a[1][2] - b[1][2];
|
Daniel@0
|
442 }
|
Daniel@0
|
443
|
Daniel@0
|
444 function minAreaHeap() {
|
Daniel@0
|
445 var heap = {},
|
Daniel@0
|
446 array = [],
|
Daniel@0
|
447 size = 0;
|
Daniel@0
|
448
|
Daniel@0
|
449 heap.push = function(object) {
|
Daniel@0
|
450 up(array[object._ = size] = object, size++);
|
Daniel@0
|
451 return size;
|
Daniel@0
|
452 };
|
Daniel@0
|
453
|
Daniel@0
|
454 heap.pop = function() {
|
Daniel@0
|
455 if (size <= 0) return;
|
Daniel@0
|
456 var removed = array[0], object;
|
Daniel@0
|
457 if (--size > 0) object = array[size], down(array[object._ = 0] = object, 0);
|
Daniel@0
|
458 return removed;
|
Daniel@0
|
459 };
|
Daniel@0
|
460
|
Daniel@0
|
461 heap.remove = function(removed) {
|
Daniel@0
|
462 var i = removed._, object;
|
Daniel@0
|
463 if (array[i] !== removed) return; // invalid request
|
Daniel@0
|
464 if (i !== --size) object = array[size], (compareArea(object, removed) < 0 ? up : down)(array[object._ = i] = object, i);
|
Daniel@0
|
465 return i;
|
Daniel@0
|
466 };
|
Daniel@0
|
467
|
Daniel@0
|
468 function up(object, i) {
|
Daniel@0
|
469 while (i > 0) {
|
Daniel@0
|
470 var j = ((i + 1) >> 1) - 1,
|
Daniel@0
|
471 parent = array[j];
|
Daniel@0
|
472 if (compareArea(object, parent) >= 0) break;
|
Daniel@0
|
473 array[parent._ = i] = parent;
|
Daniel@0
|
474 array[object._ = i = j] = object;
|
Daniel@0
|
475 }
|
Daniel@0
|
476 }
|
Daniel@0
|
477
|
Daniel@0
|
478 function down(object, i) {
|
Daniel@0
|
479 while (true) {
|
Daniel@0
|
480 var r = (i + 1) << 1,
|
Daniel@0
|
481 l = r - 1,
|
Daniel@0
|
482 j = i,
|
Daniel@0
|
483 child = array[j];
|
Daniel@0
|
484 if (l < size && compareArea(array[l], child) < 0) child = array[j = l];
|
Daniel@0
|
485 if (r < size && compareArea(array[r], child) < 0) child = array[j = r];
|
Daniel@0
|
486 if (j === i) break;
|
Daniel@0
|
487 array[child._ = i] = child;
|
Daniel@0
|
488 array[object._ = i = j] = object;
|
Daniel@0
|
489 }
|
Daniel@0
|
490 }
|
Daniel@0
|
491
|
Daniel@0
|
492 return heap;
|
Daniel@0
|
493 }
|
Daniel@0
|
494
|
Daniel@0
|
495 function transformAbsolute(transform) {
|
Daniel@0
|
496 if (!transform) return noop;
|
Daniel@0
|
497 var x0,
|
Daniel@0
|
498 y0,
|
Daniel@0
|
499 kx = transform.scale[0],
|
Daniel@0
|
500 ky = transform.scale[1],
|
Daniel@0
|
501 dx = transform.translate[0],
|
Daniel@0
|
502 dy = transform.translate[1];
|
Daniel@0
|
503 return function(point, i) {
|
Daniel@0
|
504 if (!i) x0 = y0 = 0;
|
Daniel@0
|
505 point[0] = (x0 += point[0]) * kx + dx;
|
Daniel@0
|
506 point[1] = (y0 += point[1]) * ky + dy;
|
Daniel@0
|
507 };
|
Daniel@0
|
508 }
|
Daniel@0
|
509
|
Daniel@0
|
510 function transformRelative(transform) {
|
Daniel@0
|
511 if (!transform) return noop;
|
Daniel@0
|
512 var x0,
|
Daniel@0
|
513 y0,
|
Daniel@0
|
514 kx = transform.scale[0],
|
Daniel@0
|
515 ky = transform.scale[1],
|
Daniel@0
|
516 dx = transform.translate[0],
|
Daniel@0
|
517 dy = transform.translate[1];
|
Daniel@0
|
518 return function(point, i) {
|
Daniel@0
|
519 if (!i) x0 = y0 = 0;
|
Daniel@0
|
520 var x1 = (point[0] - dx) / kx | 0,
|
Daniel@0
|
521 y1 = (point[1] - dy) / ky | 0;
|
Daniel@0
|
522 point[0] = x1 - x0;
|
Daniel@0
|
523 point[1] = y1 - y0;
|
Daniel@0
|
524 x0 = x1;
|
Daniel@0
|
525 y0 = y1;
|
Daniel@0
|
526 };
|
Daniel@0
|
527 }
|
Daniel@0
|
528
|
Daniel@0
|
529 function noop() {}
|
Daniel@0
|
530
|
Daniel@0
|
531 if (typeof define === "function" && define.amd) define(topojson);
|
Daniel@0
|
532 else if (typeof module === "object" && module.exports) module.exports = topojson;
|
Daniel@0
|
533 else this.topojson = topojson;
|
Daniel@0
|
534 }();
|