mapshaper 0.7.45 → 0.7.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/mapshaper.js +2578 -401
- package/package.json +1 -1
- package/www/mapshaper-gui.js +147 -104
- package/www/mapshaper.js +2578 -401
- package/www/page.css +33 -3
package/mapshaper.js
CHANGED
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
return obj === Object(obj); // via underscore
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
function clamp$
|
|
81
|
+
function clamp$4(val, min, max) {
|
|
82
82
|
return val < min ? min : (val > max ? max : val);
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -261,36 +261,6 @@
|
|
|
261
261
|
};
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
// Call @iter on each member of an array (similar to Array#reduce(iter))
|
|
265
|
-
// iter: function(memo, item, callback)
|
|
266
|
-
// Call @done when all members have been processed or if an error occurs
|
|
267
|
-
// done: function(err, memo)
|
|
268
|
-
// @memo: Initial value
|
|
269
|
-
//
|
|
270
|
-
function reduceAsync(arr, memo, iter, done) {
|
|
271
|
-
var call = typeof setImmediate == 'undefined' ? setTimeout : setImmediate;
|
|
272
|
-
var i=0;
|
|
273
|
-
next(null, memo);
|
|
274
|
-
|
|
275
|
-
function next(err, memo) {
|
|
276
|
-
// Detach next operation from call stack to prevent overflow
|
|
277
|
-
// Don't use setTimeout(, 0) if setImmediate is available
|
|
278
|
-
// (setTimeout() can introduce a long delay if previous operation was slow,
|
|
279
|
-
// as of Node 0.10.32 -- a bug?)
|
|
280
|
-
if (err) {
|
|
281
|
-
return done(err, null);
|
|
282
|
-
}
|
|
283
|
-
call(function() {
|
|
284
|
-
if (i < arr.length === false) {
|
|
285
|
-
done(null, memo);
|
|
286
|
-
} else {
|
|
287
|
-
iter(memo, arr[i++], next);
|
|
288
|
-
}
|
|
289
|
-
}, 0);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
|
|
294
264
|
// Append elements of @src array to @dest array
|
|
295
265
|
function merge$1(dest, src) {
|
|
296
266
|
if (!isArray(dest) || !isArray(src)) {
|
|
@@ -751,7 +721,7 @@
|
|
|
751
721
|
function findValueByRank(arr, rank) {
|
|
752
722
|
if (!arr.length || rank < 1 || rank > arr.length) error$1("[findValueByRank()] invalid input");
|
|
753
723
|
|
|
754
|
-
rank = clamp$
|
|
724
|
+
rank = clamp$4(rank | 0, 1, arr.length);
|
|
755
725
|
var k = rank - 1, // conv. rank to array index
|
|
756
726
|
n = arr.length,
|
|
757
727
|
l = 0,
|
|
@@ -1125,7 +1095,7 @@
|
|
|
1125
1095
|
// self-import and the resulting Rollup circular-dependency warning.
|
|
1126
1096
|
var utils = {
|
|
1127
1097
|
addThousandsSep, addslashes, arrayToIndex,
|
|
1128
|
-
clamp: clamp$
|
|
1098
|
+
clamp: clamp$4, cleanNumericString, contains, copyElements, countValues, createBuffer,
|
|
1129
1099
|
defaults, difference,
|
|
1130
1100
|
endsWith, every, expandoBuffer, extend: extend$1, extendBuffer,
|
|
1131
1101
|
find: find$1, findMedian, findQuantile, findRankByValue, findStringPrefix,
|
|
@@ -1145,7 +1115,7 @@
|
|
|
1145
1115
|
parseIntlNumber, parseNumber: parseNumber$1, parseString, pickOne, pluck,
|
|
1146
1116
|
pluralSuffix, promisify,
|
|
1147
1117
|
quicksort: quicksort$1, quicksortPartition,
|
|
1148
|
-
range,
|
|
1118
|
+
range, regexEscape, reorderArray: reorderArray$1, repeat, repeatString,
|
|
1149
1119
|
replaceArray, rpad, rtrim,
|
|
1150
1120
|
shuffle, some, sortArrayIndex, sortOn, splitLines, sum: sum$1,
|
|
1151
1121
|
toArray: toArray$1, toBuffer, trim, trimQuotes,
|
|
@@ -2083,12 +2053,12 @@
|
|
|
2083
2053
|
// TODO: remove this constant, use actual data from dataset CRS,
|
|
2084
2054
|
// also consider using ellipsoidal formulas where greater accuracy might be important.
|
|
2085
2055
|
var R$3 = WGS84.SEMIMAJOR_AXIS;
|
|
2086
|
-
var D2R$
|
|
2087
|
-
var R2D$
|
|
2056
|
+
var D2R$8 = Math.PI / 180;
|
|
2057
|
+
var R2D$7 = 180 / Math.PI;
|
|
2088
2058
|
|
|
2089
2059
|
// Equirectangular projection
|
|
2090
2060
|
function degreesToMeters(deg) {
|
|
2091
|
-
return deg * D2R$
|
|
2061
|
+
return deg * D2R$8 * R$3;
|
|
2092
2062
|
}
|
|
2093
2063
|
|
|
2094
2064
|
function distance3D(ax, ay, az, bx, by, bz) {
|
|
@@ -2235,16 +2205,16 @@
|
|
|
2235
2205
|
|
|
2236
2206
|
function xyzToLngLat(x, y, z, p) {
|
|
2237
2207
|
var d = distance3D(0, 0, 0, x, y, z); // normalize
|
|
2238
|
-
var lat = Math.asin(z / d) / D2R$
|
|
2239
|
-
var lng = Math.atan2(y / d, x / d) / D2R$
|
|
2208
|
+
var lat = Math.asin(z / d) / D2R$8;
|
|
2209
|
+
var lng = Math.atan2(y / d, x / d) / D2R$8;
|
|
2240
2210
|
p[0] = lng;
|
|
2241
2211
|
p[1] = lat;
|
|
2242
2212
|
}
|
|
2243
2213
|
|
|
2244
2214
|
function lngLatToXYZ(lng, lat, p) {
|
|
2245
2215
|
var cosLat;
|
|
2246
|
-
lng *= D2R$
|
|
2247
|
-
lat *= D2R$
|
|
2216
|
+
lng *= D2R$8;
|
|
2217
|
+
lat *= D2R$8;
|
|
2248
2218
|
cosLat = Math.cos(lat);
|
|
2249
2219
|
p[0] = Math.cos(lng) * cosLat * R$3;
|
|
2250
2220
|
p[1] = Math.sin(lng) * cosLat * R$3;
|
|
@@ -2364,9 +2334,9 @@
|
|
|
2364
2334
|
|
|
2365
2335
|
var Geom = /*#__PURE__*/Object.freeze({
|
|
2366
2336
|
__proto__: null,
|
|
2367
|
-
D2R: D2R$
|
|
2337
|
+
D2R: D2R$8,
|
|
2368
2338
|
R: R$3,
|
|
2369
|
-
R2D: R2D$
|
|
2339
|
+
R2D: R2D$7,
|
|
2370
2340
|
bearing: bearing,
|
|
2371
2341
|
bearing2D: bearing2D,
|
|
2372
2342
|
containsBounds: containsBounds,
|
|
@@ -6294,9 +6264,9 @@
|
|
|
6294
6264
|
* ISC License: https://github.com/d3/d3-geo-polygon/blob/main/LICENSE
|
|
6295
6265
|
*/
|
|
6296
6266
|
|
|
6297
|
-
var D2R$
|
|
6298
|
-
var R2D$
|
|
6299
|
-
var EPS$
|
|
6267
|
+
var D2R$7 = Math.PI / 180;
|
|
6268
|
+
var R2D$6 = 180 / Math.PI;
|
|
6269
|
+
var EPS$3 = 1e-12;
|
|
6300
6270
|
|
|
6301
6271
|
// Build a forward-only spherical polyhedral projection.
|
|
6302
6272
|
//
|
|
@@ -6334,10 +6304,10 @@
|
|
|
6334
6304
|
throw new Error('Invalid polyhedral face tree');
|
|
6335
6305
|
}
|
|
6336
6306
|
var childEdge = shared.map(function(p) {
|
|
6337
|
-
return face.project(p[0] * D2R$
|
|
6307
|
+
return face.project(p[0] * D2R$7, p[1] * D2R$7);
|
|
6338
6308
|
});
|
|
6339
6309
|
var parentEdge = shared.map(function(p) {
|
|
6340
|
-
return parent.project(p[0] * D2R$
|
|
6310
|
+
return parent.project(p[0] * D2R$7, p[1] * D2R$7);
|
|
6341
6311
|
});
|
|
6342
6312
|
face.transform = multiplyMatrices(
|
|
6343
6313
|
parent.transform,
|
|
@@ -6348,12 +6318,12 @@
|
|
|
6348
6318
|
|
|
6349
6319
|
var rootEdge = findLongestEdge(faces[0].coords);
|
|
6350
6320
|
var rootPlanarEdge = rootEdge.map(function(p) {
|
|
6351
|
-
return faces[0].project(p[0] * D2R$
|
|
6321
|
+
return faces[0].project(p[0] * D2R$7, p[1] * D2R$7);
|
|
6352
6322
|
});
|
|
6353
6323
|
var sphericalEdgeLength = angularDistance(rootEdge[0], rootEdge[1]);
|
|
6354
6324
|
var planarEdgeLength = distance2D(rootPlanarEdge[0], rootPlanarEdge[1]);
|
|
6355
6325
|
var scale = sphericalEdgeLength / planarEdgeLength;
|
|
6356
|
-
var planarAngle = (config.angle || 0) * D2R$
|
|
6326
|
+
var planarAngle = (config.angle || 0) * D2R$7;
|
|
6357
6327
|
var edgeIndex = indexEdges(faces, attachedPairs);
|
|
6358
6328
|
var outline = buildOutline(faces, attachedPairs).map(function(ring) {
|
|
6359
6329
|
return ring.map(transformOutputPoint);
|
|
@@ -6374,6 +6344,7 @@
|
|
|
6374
6344
|
faces: faces,
|
|
6375
6345
|
outline: outline,
|
|
6376
6346
|
forward: forward,
|
|
6347
|
+
forwardFace: forwardFace,
|
|
6377
6348
|
findFace: findFace,
|
|
6378
6349
|
findTransitionRegion: findTransitionRegion,
|
|
6379
6350
|
getTopology: getTopology
|
|
@@ -6383,14 +6354,30 @@
|
|
|
6383
6354
|
var rotated = rotateRadians(
|
|
6384
6355
|
lam,
|
|
6385
6356
|
phi,
|
|
6386
|
-
config.rotation[0] * D2R$
|
|
6387
|
-
config.rotation[1] * D2R$
|
|
6388
|
-
config.rotation[2] * D2R$
|
|
6357
|
+
config.rotation[0] * D2R$7,
|
|
6358
|
+
config.rotation[1] * D2R$7,
|
|
6359
|
+
config.rotation[2] * D2R$7
|
|
6389
6360
|
);
|
|
6390
6361
|
var face = findFaceRotated(rotated[0], rotated[1]);
|
|
6391
6362
|
if (!face) return null;
|
|
6392
|
-
|
|
6393
|
-
|
|
6363
|
+
return projectFacePoint(face, rotated[0], rotated[1]);
|
|
6364
|
+
}
|
|
6365
|
+
|
|
6366
|
+
function forwardFace(lam, phi, faceId) {
|
|
6367
|
+
var rotated = rotateRadians(
|
|
6368
|
+
lam,
|
|
6369
|
+
phi,
|
|
6370
|
+
config.rotation[0] * D2R$7,
|
|
6371
|
+
config.rotation[1] * D2R$7,
|
|
6372
|
+
config.rotation[2] * D2R$7
|
|
6373
|
+
);
|
|
6374
|
+
var face = faces[faceId];
|
|
6375
|
+
return face ? projectFacePoint(face, rotated[0], rotated[1]) : null;
|
|
6376
|
+
}
|
|
6377
|
+
|
|
6378
|
+
function projectFacePoint(face, lam, phi) {
|
|
6379
|
+
var p = face.project(lam, phi);
|
|
6380
|
+
p = applyMatrix$1(face.transform, p);
|
|
6394
6381
|
p = transformOutputPoint(p);
|
|
6395
6382
|
p[0] -= centerX;
|
|
6396
6383
|
p[1] -= centerY;
|
|
@@ -6401,9 +6388,9 @@
|
|
|
6401
6388
|
var rotated = rotateRadians(
|
|
6402
6389
|
lam,
|
|
6403
6390
|
phi,
|
|
6404
|
-
config.rotation[0] * D2R$
|
|
6405
|
-
config.rotation[1] * D2R$
|
|
6406
|
-
config.rotation[2] * D2R$
|
|
6391
|
+
config.rotation[0] * D2R$7,
|
|
6392
|
+
config.rotation[1] * D2R$7,
|
|
6393
|
+
config.rotation[2] * D2R$7
|
|
6407
6394
|
);
|
|
6408
6395
|
var face = findFaceRotated(rotated[0], rotated[1]);
|
|
6409
6396
|
return face ? face.id : -1;
|
|
@@ -6413,9 +6400,9 @@
|
|
|
6413
6400
|
var rotated = rotateRadians(
|
|
6414
6401
|
lam,
|
|
6415
6402
|
phi,
|
|
6416
|
-
config.rotation[0] * D2R$
|
|
6417
|
-
config.rotation[1] * D2R$
|
|
6418
|
-
config.rotation[2] * D2R$
|
|
6403
|
+
config.rotation[0] * D2R$7,
|
|
6404
|
+
config.rotation[1] * D2R$7,
|
|
6405
|
+
config.rotation[2] * D2R$7
|
|
6419
6406
|
);
|
|
6420
6407
|
var face = findFaceRotated(rotated[0], rotated[1]);
|
|
6421
6408
|
var region;
|
|
@@ -6432,7 +6419,7 @@
|
|
|
6432
6419
|
faceId = config.findFace(lam, phi);
|
|
6433
6420
|
return faceId >= 0 ? faces[faceId] : null;
|
|
6434
6421
|
}
|
|
6435
|
-
var p = radiansToVector(lam, phi);
|
|
6422
|
+
var p = radiansToVector$1(lam, phi);
|
|
6436
6423
|
for (var i = 0; i < faces.length; i++) {
|
|
6437
6424
|
if (faceContainsVector(faces[i], p)) return faces[i];
|
|
6438
6425
|
}
|
|
@@ -6457,16 +6444,16 @@
|
|
|
6457
6444
|
var seams = edgeIndex.map(function(edge) {
|
|
6458
6445
|
var endpoints = edge.points.map(function(p) {
|
|
6459
6446
|
var q = rotateRadians(
|
|
6460
|
-
p[0] * D2R$
|
|
6461
|
-
p[1] * D2R$
|
|
6462
|
-
config.rotation[0] * D2R$
|
|
6463
|
-
config.rotation[1] * D2R$
|
|
6464
|
-
config.rotation[2] * D2R$
|
|
6447
|
+
p[0] * D2R$7,
|
|
6448
|
+
p[1] * D2R$7,
|
|
6449
|
+
config.rotation[0] * D2R$7,
|
|
6450
|
+
config.rotation[1] * D2R$7,
|
|
6451
|
+
config.rotation[2] * D2R$7,
|
|
6465
6452
|
true
|
|
6466
6453
|
);
|
|
6467
|
-
return [normalizeLongitude$
|
|
6454
|
+
return [normalizeLongitude$3(q[0] * R2D$6 + lon0), q[1] * R2D$6];
|
|
6468
6455
|
});
|
|
6469
|
-
var paths = splitPathAtAntimeridian$
|
|
6456
|
+
var paths = splitPathAtAntimeridian$2(
|
|
6470
6457
|
interpolateGreatCircle(endpoints[0], endpoints[1], 0.05)
|
|
6471
6458
|
);
|
|
6472
6459
|
paths.forEach(function(path) {
|
|
@@ -6487,16 +6474,23 @@
|
|
|
6487
6474
|
});
|
|
6488
6475
|
return {
|
|
6489
6476
|
regions: faces.map(function(face) {
|
|
6490
|
-
return {
|
|
6477
|
+
return {
|
|
6478
|
+
id: face.id,
|
|
6479
|
+
projected_boundary: getProjectedFaceBoundary(face)
|
|
6480
|
+
};
|
|
6491
6481
|
}),
|
|
6492
6482
|
seams: seams,
|
|
6493
6483
|
findRegion: function(lon, lat) {
|
|
6494
|
-
var lam = normalizeLongitude$
|
|
6495
|
-
return findFace(lam, lat * D2R$
|
|
6484
|
+
var lam = normalizeLongitude$3(lon - lon0) * D2R$7;
|
|
6485
|
+
return findFace(lam, lat * D2R$7);
|
|
6496
6486
|
},
|
|
6497
6487
|
findTransitionRegion: function(lon, lat) {
|
|
6498
|
-
var lam = normalizeLongitude$
|
|
6499
|
-
return findTransitionRegion(lam, lat * D2R$
|
|
6488
|
+
var lam = normalizeLongitude$3(lon - lon0) * D2R$7;
|
|
6489
|
+
return findTransitionRegion(lam, lat * D2R$7);
|
|
6490
|
+
},
|
|
6491
|
+
projectRegion: function(lon, lat, regionId) {
|
|
6492
|
+
var lam = normalizeLongitude$3(lon - lon0) * D2R$7;
|
|
6493
|
+
return forwardFace(lam, lat * D2R$7, regionId);
|
|
6500
6494
|
},
|
|
6501
6495
|
regionsAreAttached: function(a, b) {
|
|
6502
6496
|
return regionPairs.get(pairKey(a, b)) === true;
|
|
@@ -6508,15 +6502,29 @@
|
|
|
6508
6502
|
})
|
|
6509
6503
|
};
|
|
6510
6504
|
}
|
|
6505
|
+
|
|
6506
|
+
function getProjectedFaceBoundary(face) {
|
|
6507
|
+
var ring = [];
|
|
6508
|
+
for (var i = 0; i < face.coords.length; i++) {
|
|
6509
|
+
var a = face.coords[i];
|
|
6510
|
+
var b = face.coords[(i + 1) % face.coords.length];
|
|
6511
|
+
var edge = interpolateGreatCircle(a, b, 0.5);
|
|
6512
|
+
for (var j = 0; j < edge.length - 1; j++) {
|
|
6513
|
+
ring.push(projectFacePoint(face, edge[j][0] * D2R$7, edge[j][1] * D2R$7));
|
|
6514
|
+
}
|
|
6515
|
+
}
|
|
6516
|
+
ring.push(ring[0].concat());
|
|
6517
|
+
return ring;
|
|
6518
|
+
}
|
|
6511
6519
|
}
|
|
6512
6520
|
|
|
6513
6521
|
function rotateSphericalRadians(lam, phi, rotation, invert) {
|
|
6514
6522
|
return rotateRadians(
|
|
6515
6523
|
lam,
|
|
6516
6524
|
phi,
|
|
6517
|
-
(rotation[0] || 0) * D2R$
|
|
6518
|
-
(rotation[1] || 0) * D2R$
|
|
6519
|
-
(rotation[2] || 0) * D2R$
|
|
6525
|
+
(rotation[0] || 0) * D2R$7,
|
|
6526
|
+
(rotation[1] || 0) * D2R$7,
|
|
6527
|
+
(rotation[2] || 0) * D2R$7,
|
|
6520
6528
|
invert
|
|
6521
6529
|
);
|
|
6522
6530
|
}
|
|
@@ -6525,7 +6533,7 @@
|
|
|
6525
6533
|
var vectors = coords.map(function(p) {
|
|
6526
6534
|
return degreesToVector$2(p[0], p[1]);
|
|
6527
6535
|
});
|
|
6528
|
-
var inside = normalizeVector$
|
|
6536
|
+
var inside = normalizeVector$2(vectors.reduce(function(sum, p) {
|
|
6529
6537
|
sum[0] += p[0];
|
|
6530
6538
|
sum[1] += p[1];
|
|
6531
6539
|
sum[2] += p[2];
|
|
@@ -6535,10 +6543,10 @@
|
|
|
6535
6543
|
for (var i = 0; i < vectors.length; i++) {
|
|
6536
6544
|
var a = vectors[i];
|
|
6537
6545
|
var b = vectors[(i + 1) % vectors.length];
|
|
6538
|
-
var normal = cross$
|
|
6546
|
+
var normal = cross$2(a, b);
|
|
6539
6547
|
edges.push({
|
|
6540
6548
|
normal: normal,
|
|
6541
|
-
sign: dot$
|
|
6549
|
+
sign: dot$2(normal, inside) < 0 ? -1 : 1
|
|
6542
6550
|
});
|
|
6543
6551
|
}
|
|
6544
6552
|
return {
|
|
@@ -6553,7 +6561,7 @@
|
|
|
6553
6561
|
function faceContainsVector(face, p) {
|
|
6554
6562
|
for (var i = 0; i < face.edges.length; i++) {
|
|
6555
6563
|
var edge = face.edges[i];
|
|
6556
|
-
if (dot$
|
|
6564
|
+
if (dot$2(edge.normal, p) * edge.sign < -EPS$3) return false;
|
|
6557
6565
|
}
|
|
6558
6566
|
return true;
|
|
6559
6567
|
}
|
|
@@ -6589,8 +6597,8 @@
|
|
|
6589
6597
|
var adjacent = findAdjacentFace(faces, face.id, a, b);
|
|
6590
6598
|
if (adjacent >= 0 && attachedPairs.has(pairKey(face.id, adjacent))) continue;
|
|
6591
6599
|
edges.push([
|
|
6592
|
-
applyMatrix(face.transform, face.project(a[0] * D2R$
|
|
6593
|
-
applyMatrix(face.transform, face.project(b[0] * D2R$
|
|
6600
|
+
applyMatrix$1(face.transform, face.project(a[0] * D2R$7, a[1] * D2R$7)),
|
|
6601
|
+
applyMatrix$1(face.transform, face.project(b[0] * D2R$7, b[1] * D2R$7))
|
|
6594
6602
|
]);
|
|
6595
6603
|
}
|
|
6596
6604
|
});
|
|
@@ -6707,7 +6715,7 @@
|
|
|
6707
6715
|
];
|
|
6708
6716
|
}
|
|
6709
6717
|
|
|
6710
|
-
function applyMatrix(m, p) {
|
|
6718
|
+
function applyMatrix$1(m, p) {
|
|
6711
6719
|
return [
|
|
6712
6720
|
m[0] * p[0] + m[1] * p[1] + m[2],
|
|
6713
6721
|
m[3] * p[0] + m[4] * p[1] + m[5]
|
|
@@ -6717,9 +6725,9 @@
|
|
|
6717
6725
|
function rotateRadians(lam, phi, deltaLam, deltaPhi, deltaGamma, invert) {
|
|
6718
6726
|
if (invert) {
|
|
6719
6727
|
var inv = rotatePhiGamma$1(lam, phi, deltaPhi, deltaGamma, true);
|
|
6720
|
-
return [normalizeRadians$
|
|
6728
|
+
return [normalizeRadians$2(inv[0] - deltaLam), inv[1]];
|
|
6721
6729
|
}
|
|
6722
|
-
lam = normalizeRadians$
|
|
6730
|
+
lam = normalizeRadians$2(lam + deltaLam);
|
|
6723
6731
|
return rotatePhiGamma$1(lam, phi, deltaPhi, deltaGamma, false);
|
|
6724
6732
|
}
|
|
6725
6733
|
|
|
@@ -6739,28 +6747,28 @@
|
|
|
6739
6747
|
return [
|
|
6740
6748
|
Math.atan2(y * cosDeltaGamma + z * sinDeltaGamma,
|
|
6741
6749
|
x * cosDeltaPhi + k * sinDeltaPhi),
|
|
6742
|
-
Math.asin(clamp$
|
|
6750
|
+
Math.asin(clamp$3(k * cosDeltaPhi - x * sinDeltaPhi, -1, 1))
|
|
6743
6751
|
];
|
|
6744
6752
|
}
|
|
6745
6753
|
k = z * cosDeltaPhi + x * sinDeltaPhi;
|
|
6746
6754
|
return [
|
|
6747
6755
|
Math.atan2(y * cosDeltaGamma - k * sinDeltaGamma,
|
|
6748
6756
|
x * cosDeltaPhi - z * sinDeltaPhi),
|
|
6749
|
-
Math.asin(clamp$
|
|
6757
|
+
Math.asin(clamp$3(k * cosDeltaGamma + y * sinDeltaGamma, -1, 1))
|
|
6750
6758
|
];
|
|
6751
6759
|
}
|
|
6752
6760
|
|
|
6753
6761
|
function interpolateGreatCircle(a, b, interval) {
|
|
6754
6762
|
var av = degreesToVector$2(a[0], a[1]);
|
|
6755
6763
|
var bv = degreesToVector$2(b[0], b[1]);
|
|
6756
|
-
var angle = Math.acos(clamp$
|
|
6757
|
-
var n = Math.max(1, Math.ceil(angle * R2D$
|
|
6764
|
+
var angle = Math.acos(clamp$3(dot$2(av, bv), -1, 1));
|
|
6765
|
+
var n = Math.max(1, Math.ceil(angle * R2D$6 / interval));
|
|
6758
6766
|
var sinAngle = Math.sin(angle);
|
|
6759
6767
|
var points = [];
|
|
6760
6768
|
for (var i = 0; i <= n; i++) {
|
|
6761
6769
|
var t = i / n;
|
|
6762
6770
|
var p;
|
|
6763
|
-
if (sinAngle < EPS$
|
|
6771
|
+
if (sinAngle < EPS$3) {
|
|
6764
6772
|
p = av;
|
|
6765
6773
|
} else {
|
|
6766
6774
|
var ka = Math.sin((1 - t) * angle) / sinAngle;
|
|
@@ -6771,12 +6779,12 @@
|
|
|
6771
6779
|
av[2] * ka + bv[2] * kb
|
|
6772
6780
|
];
|
|
6773
6781
|
}
|
|
6774
|
-
points.push(vectorToDegrees$2(normalizeVector$
|
|
6782
|
+
points.push(vectorToDegrees$2(normalizeVector$2(p)));
|
|
6775
6783
|
}
|
|
6776
6784
|
return points;
|
|
6777
6785
|
}
|
|
6778
6786
|
|
|
6779
|
-
function splitPathAtAntimeridian$
|
|
6787
|
+
function splitPathAtAntimeridian$2(path) {
|
|
6780
6788
|
var paths = [];
|
|
6781
6789
|
var part = [path[0]];
|
|
6782
6790
|
for (var i = 1; i < path.length; i++) {
|
|
@@ -6812,32 +6820,32 @@
|
|
|
6812
6820
|
}
|
|
6813
6821
|
|
|
6814
6822
|
function angularDistance(a, b) {
|
|
6815
|
-
return Math.acos(clamp$
|
|
6823
|
+
return Math.acos(clamp$3(dot$2(degreesToVector$2(a[0], a[1]),
|
|
6816
6824
|
degreesToVector$2(b[0], b[1])), -1, 1));
|
|
6817
6825
|
}
|
|
6818
6826
|
|
|
6819
6827
|
function degreesToVector$2(lon, lat) {
|
|
6820
|
-
return radiansToVector(lon * D2R$
|
|
6828
|
+
return radiansToVector$1(lon * D2R$7, lat * D2R$7);
|
|
6821
6829
|
}
|
|
6822
6830
|
|
|
6823
|
-
function radiansToVector(lam, phi) {
|
|
6831
|
+
function radiansToVector$1(lam, phi) {
|
|
6824
6832
|
var cosPhi = Math.cos(phi);
|
|
6825
6833
|
return [Math.cos(lam) * cosPhi, Math.sin(lam) * cosPhi, Math.sin(phi)];
|
|
6826
6834
|
}
|
|
6827
6835
|
|
|
6828
6836
|
function vectorToDegrees$2(p) {
|
|
6829
6837
|
return [
|
|
6830
|
-
Math.atan2(p[1], p[0]) * R2D$
|
|
6831
|
-
Math.asin(clamp$
|
|
6838
|
+
Math.atan2(p[1], p[0]) * R2D$6,
|
|
6839
|
+
Math.asin(clamp$3(p[2], -1, 1)) * R2D$6
|
|
6832
6840
|
];
|
|
6833
6841
|
}
|
|
6834
6842
|
|
|
6835
|
-
function normalizeVector$
|
|
6836
|
-
var k = 1 / Math.sqrt(dot$
|
|
6843
|
+
function normalizeVector$2(p) {
|
|
6844
|
+
var k = 1 / Math.sqrt(dot$2(p, p));
|
|
6837
6845
|
return [p[0] * k, p[1] * k, p[2] * k];
|
|
6838
6846
|
}
|
|
6839
6847
|
|
|
6840
|
-
function cross$
|
|
6848
|
+
function cross$2(a, b) {
|
|
6841
6849
|
return [
|
|
6842
6850
|
a[1] * b[2] - a[2] * b[1],
|
|
6843
6851
|
a[2] * b[0] - a[0] * b[2],
|
|
@@ -6845,7 +6853,7 @@
|
|
|
6845
6853
|
];
|
|
6846
6854
|
}
|
|
6847
6855
|
|
|
6848
|
-
function dot$
|
|
6856
|
+
function dot$2(a, b) {
|
|
6849
6857
|
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
6850
6858
|
}
|
|
6851
6859
|
|
|
@@ -6856,7 +6864,7 @@
|
|
|
6856
6864
|
}
|
|
6857
6865
|
|
|
6858
6866
|
function sameSphericalPoint(a, b) {
|
|
6859
|
-
return Math.abs(a[0] - b[0]) < EPS$
|
|
6867
|
+
return Math.abs(a[0] - b[0]) < EPS$3 && Math.abs(a[1] - b[1]) < EPS$3;
|
|
6860
6868
|
}
|
|
6861
6869
|
|
|
6862
6870
|
function pointsAlmostEqual(a, b) {
|
|
@@ -6877,19 +6885,19 @@
|
|
|
6877
6885
|
return a < b ? a + '~' + b : b + '~' + a;
|
|
6878
6886
|
}
|
|
6879
6887
|
|
|
6880
|
-
function normalizeRadians$
|
|
6888
|
+
function normalizeRadians$2(lam) {
|
|
6881
6889
|
while (lam > Math.PI) lam -= Math.PI * 2;
|
|
6882
6890
|
while (lam < -Math.PI) lam += Math.PI * 2;
|
|
6883
6891
|
return lam;
|
|
6884
6892
|
}
|
|
6885
6893
|
|
|
6886
|
-
function normalizeLongitude$
|
|
6894
|
+
function normalizeLongitude$3(lon) {
|
|
6887
6895
|
while (lon > 180) lon -= 360;
|
|
6888
6896
|
while (lon < -180) lon += 360;
|
|
6889
6897
|
return lon;
|
|
6890
6898
|
}
|
|
6891
6899
|
|
|
6892
|
-
function clamp$
|
|
6900
|
+
function clamp$3(val, min, max) {
|
|
6893
6901
|
return Math.max(min, Math.min(max, val));
|
|
6894
6902
|
}
|
|
6895
6903
|
|
|
@@ -6905,9 +6913,9 @@
|
|
|
6905
6913
|
*/
|
|
6906
6914
|
|
|
6907
6915
|
|
|
6908
|
-
var D2R$
|
|
6909
|
-
var R2D$
|
|
6910
|
-
var SQRT3 = Math.sqrt(3);
|
|
6916
|
+
var D2R$6 = Math.PI / 180;
|
|
6917
|
+
var R2D$5 = 180 / Math.PI;
|
|
6918
|
+
var SQRT3$2 = Math.sqrt(3);
|
|
6911
6919
|
var GRAY_Z = Math.sqrt(5 + 2 * Math.sqrt(5)) / Math.sqrt(15);
|
|
6912
6920
|
var GRAY_EL = Math.sqrt(8) / Math.sqrt(5 + Math.sqrt(5));
|
|
6913
6921
|
var GRAY_DVE = Math.sqrt(3 + Math.sqrt(5)) / Math.sqrt(5 + Math.sqrt(5));
|
|
@@ -6919,7 +6927,7 @@
|
|
|
6919
6927
|
6, 8, 10, 17, 21,
|
|
6920
6928
|
16, 15, 19, 19
|
|
6921
6929
|
];
|
|
6922
|
-
var engines$
|
|
6930
|
+
var engines$3 = {};
|
|
6923
6931
|
|
|
6924
6932
|
function registerDymaxionProjections(mproj) {
|
|
6925
6933
|
// Some unit tests import source modules directly in an ESM context where
|
|
@@ -6938,9 +6946,9 @@
|
|
|
6938
6946
|
|
|
6939
6947
|
function getDymaxionEngine(method) {
|
|
6940
6948
|
method = method || 'fuller';
|
|
6941
|
-
if (!engines$
|
|
6949
|
+
if (!engines$3[method]) {
|
|
6942
6950
|
var data = createAiroceanFaces();
|
|
6943
|
-
engines$
|
|
6951
|
+
engines$3[method] = createPolyhedralProjection({
|
|
6944
6952
|
faces: data.faces,
|
|
6945
6953
|
faceSites: data.sites,
|
|
6946
6954
|
parents: PARENTS,
|
|
@@ -6951,7 +6959,7 @@
|
|
|
6951
6959
|
createGrayFullerFaceProjector
|
|
6952
6960
|
});
|
|
6953
6961
|
}
|
|
6954
|
-
return engines$
|
|
6962
|
+
return engines$3[method];
|
|
6955
6963
|
}
|
|
6956
6964
|
|
|
6957
6965
|
function initDymaxion(P, method) {
|
|
@@ -6967,12 +6975,12 @@
|
|
|
6967
6975
|
xy.y = p[1];
|
|
6968
6976
|
}
|
|
6969
6977
|
};
|
|
6970
|
-
P.__projection_topology = engine.getTopology(P.lam0 * R2D$
|
|
6978
|
+
P.__projection_topology = engine.getTopology(P.lam0 * R2D$5);
|
|
6971
6979
|
P.__projected_outline = engine.outline;
|
|
6972
6980
|
}
|
|
6973
6981
|
|
|
6974
6982
|
function createAiroceanFaces() {
|
|
6975
|
-
var theta = Math.atan(0.5) * R2D$
|
|
6983
|
+
var theta = Math.atan(0.5) * R2D$5;
|
|
6976
6984
|
var vertices = [[0, 90], [0, -90]];
|
|
6977
6985
|
var faces;
|
|
6978
6986
|
var sites;
|
|
@@ -7069,10 +7077,10 @@
|
|
|
7069
7077
|
var s = GRAY_Z / (cosPhi * Math.cos(lam));
|
|
7070
7078
|
var x = cosPhi * Math.sin(lam) * s;
|
|
7071
7079
|
var y = Math.sin(phi) * s;
|
|
7072
|
-
var a1p = Math.atan2(2 * y / SQRT3 + GRAY_EL / 3 - GRAY_EL / 2, GRAY_DVE);
|
|
7073
|
-
var a2p = Math.atan2(x - y / SQRT3 + GRAY_EL / 3 - GRAY_EL / 2, GRAY_DVE);
|
|
7074
|
-
var a3p = Math.atan2(GRAY_EL / 3 - x - y / SQRT3 - GRAY_EL / 2, GRAY_DVE);
|
|
7075
|
-
return [SQRT3 * (a2p - a3p), 2 * a1p - a2p - a3p];
|
|
7080
|
+
var a1p = Math.atan2(2 * y / SQRT3$2 + GRAY_EL / 3 - GRAY_EL / 2, GRAY_DVE);
|
|
7081
|
+
var a2p = Math.atan2(x - y / SQRT3$2 + GRAY_EL / 3 - GRAY_EL / 2, GRAY_DVE);
|
|
7082
|
+
var a3p = Math.atan2(GRAY_EL / 3 - x - y / SQRT3$2 - GRAY_EL / 2, GRAY_DVE);
|
|
7083
|
+
return [SQRT3$2 * (a2p - a3p), 2 * a1p - a2p - a3p];
|
|
7076
7084
|
}
|
|
7077
7085
|
|
|
7078
7086
|
function getSphericalCentroid(coords) {
|
|
@@ -7097,16 +7105,16 @@
|
|
|
7097
7105
|
}
|
|
7098
7106
|
|
|
7099
7107
|
function degreesToVector$1(p) {
|
|
7100
|
-
var lam = p[0] * D2R$
|
|
7101
|
-
var phi = p[1] * D2R$
|
|
7108
|
+
var lam = p[0] * D2R$6;
|
|
7109
|
+
var phi = p[1] * D2R$6;
|
|
7102
7110
|
var cosPhi = Math.cos(phi);
|
|
7103
7111
|
return [Math.cos(lam) * cosPhi, Math.sin(lam) * cosPhi, Math.sin(phi)];
|
|
7104
7112
|
}
|
|
7105
7113
|
|
|
7106
7114
|
function vectorToDegrees$1(p) {
|
|
7107
7115
|
return [
|
|
7108
|
-
Math.atan2(p[1], p[0]) * R2D$
|
|
7109
|
-
Math.asin(Math.max(-1, Math.min(1, p[2]))) * R2D$
|
|
7116
|
+
Math.atan2(p[1], p[0]) * R2D$5,
|
|
7117
|
+
Math.asin(Math.max(-1, Math.min(1, p[2]))) * R2D$5
|
|
7110
7118
|
];
|
|
7111
7119
|
}
|
|
7112
7120
|
|
|
@@ -7154,8 +7162,8 @@
|
|
|
7154
7162
|
* ISC License: https://github.com/d3/d3-geo-polygon/blob/main/LICENSE
|
|
7155
7163
|
*/
|
|
7156
7164
|
|
|
7157
|
-
var D2R$
|
|
7158
|
-
var R2D$
|
|
7165
|
+
var D2R$5 = Math.PI / 180;
|
|
7166
|
+
var R2D$4 = 180 / Math.PI;
|
|
7159
7167
|
|
|
7160
7168
|
function createCahillKeyesRaw(mg) {
|
|
7161
7169
|
return createCahillKeyesTransform(mg, false);
|
|
@@ -7167,12 +7175,12 @@
|
|
|
7167
7175
|
|
|
7168
7176
|
return function(lambda, phi) {
|
|
7169
7177
|
if (faceOnly) {
|
|
7170
|
-
var lon = lambda * R2D$
|
|
7178
|
+
var lon = lambda * R2D$4;
|
|
7171
7179
|
var side = lon < 0 ? -1 : lon > 0 ? 1 : 0;
|
|
7172
|
-
var local = mp2xy(Math.abs(lon), Math.abs(phi * R2D$
|
|
7180
|
+
var local = mp2xy(Math.abs(lon), Math.abs(phi * R2D$4));
|
|
7173
7181
|
return [local[0], side * local[1]];
|
|
7174
7182
|
}
|
|
7175
|
-
var res = ll2mp(lambda * R2D$
|
|
7183
|
+
var res = ll2mp(lambda * R2D$4, phi * R2D$4);
|
|
7176
7184
|
var xy = mp2xy(res[0], res[1]);
|
|
7177
7185
|
var p = [xy[0], res[2] * xy[1]];
|
|
7178
7186
|
return mj2g(p, res[3]);
|
|
@@ -7190,7 +7198,7 @@
|
|
|
7190
7198
|
CK.cos60 = 0.5;
|
|
7191
7199
|
CK.pointM = [0, 0];
|
|
7192
7200
|
CK.pointG = [CK.lengthMG, 0];
|
|
7193
|
-
pointN = [CK.lengthMG, CK.lengthMG * Math.tan(30 * D2R$
|
|
7201
|
+
pointN = [CK.lengthMG, CK.lengthMG * Math.tan(30 * D2R$5)];
|
|
7194
7202
|
CK.pointA = [CK.lengthMA, 0];
|
|
7195
7203
|
CK.pointB = lineIntersection(CK.pointM, 30, CK.pointA, 45);
|
|
7196
7204
|
CK.lengthAG = distance(CK.pointA, CK.pointG);
|
|
@@ -7201,8 +7209,8 @@
|
|
|
7201
7209
|
CK.pointD = interpolate(lengthMB, lengthMN, pointN, CK.pointM);
|
|
7202
7210
|
CK.pointF = [CK.lengthMG, lengthNG - lengthMB];
|
|
7203
7211
|
CK.pointE = [
|
|
7204
|
-
pointN[0] - CK.lengthMA * Math.sin(30 * D2R$
|
|
7205
|
-
pointN[1] - CK.lengthMA * Math.cos(30 * D2R$
|
|
7212
|
+
pointN[0] - CK.lengthMA * Math.sin(30 * D2R$5),
|
|
7213
|
+
pointN[1] - CK.lengthMA * Math.cos(30 * D2R$5)
|
|
7206
7214
|
];
|
|
7207
7215
|
CK.lengthGF = distance(CK.pointG, CK.pointF);
|
|
7208
7216
|
CK.lengthBD = distance(CK.pointB, CK.pointD);
|
|
@@ -7212,8 +7220,8 @@
|
|
|
7212
7220
|
CK.lengthAP73 = CK.lengthMG - CK.lengthMA -
|
|
7213
7221
|
CK.lengthParallel0to73At0 * 73;
|
|
7214
7222
|
pointU = [
|
|
7215
|
-
CK.pointA[0] + CK.lengthAP73 * Math.cos(30 * D2R$
|
|
7216
|
-
CK.pointA[1] + CK.lengthAP73 * Math.sin(30 * D2R$
|
|
7223
|
+
CK.pointA[0] + CK.lengthAP73 * Math.cos(30 * D2R$5),
|
|
7224
|
+
CK.pointA[1] + CK.lengthAP73 * Math.sin(30 * D2R$5)
|
|
7217
7225
|
];
|
|
7218
7226
|
CK.pointT = lineIntersection(pointU, -60, CK.pointB, 30);
|
|
7219
7227
|
|
|
@@ -7454,8 +7462,8 @@
|
|
|
7454
7462
|
|
|
7455
7463
|
function radialPoint(origin, length, angle) {
|
|
7456
7464
|
return [
|
|
7457
|
-
origin[0] + length * Math.cos(angle * D2R$
|
|
7458
|
-
origin[1] + length * Math.sin(angle * D2R$
|
|
7465
|
+
origin[0] + length * Math.cos(angle * D2R$5),
|
|
7466
|
+
origin[1] + length * Math.sin(angle * D2R$5)
|
|
7459
7467
|
];
|
|
7460
7468
|
}
|
|
7461
7469
|
|
|
@@ -7472,8 +7480,8 @@
|
|
|
7472
7480
|
-xy[0] * CK.sin60 - xy[1] * CK.cos60
|
|
7473
7481
|
];
|
|
7474
7482
|
}
|
|
7475
|
-
var cos = Math.cos(angle * D2R$
|
|
7476
|
-
var sin = Math.sin(angle * D2R$
|
|
7483
|
+
var cos = Math.cos(angle * D2R$5);
|
|
7484
|
+
var sin = Math.sin(angle * D2R$5);
|
|
7477
7485
|
return [xy[0] * cos - xy[1] * sin, xy[0] * sin + xy[1] * cos];
|
|
7478
7486
|
}
|
|
7479
7487
|
}
|
|
@@ -7494,8 +7502,8 @@
|
|
|
7494
7502
|
}
|
|
7495
7503
|
|
|
7496
7504
|
function lineIntersection(p1, slope1, p2, slope2) {
|
|
7497
|
-
var m1 = Math.tan(slope1 * D2R$
|
|
7498
|
-
var m2 = Math.tan(slope2 * D2R$
|
|
7505
|
+
var m1 = Math.tan(slope1 * D2R$5);
|
|
7506
|
+
var m2 = Math.tan(slope2 * D2R$5);
|
|
7499
7507
|
var x = (m1 * p1[0] - m2 * p2[0] - p1[1] + p2[1]) / (m1 - m2);
|
|
7500
7508
|
return [x, m1 * (x - p1[0]) + p1[1]];
|
|
7501
7509
|
}
|
|
@@ -7523,8 +7531,8 @@
|
|
|
7523
7531
|
return n > 0 ? Math.floor(n) : Math.ceil(n);
|
|
7524
7532
|
}
|
|
7525
7533
|
|
|
7526
|
-
var D2R$
|
|
7527
|
-
var EPS = 1e-12;
|
|
7534
|
+
var D2R$4 = Math.PI / 180;
|
|
7535
|
+
var EPS$2 = 1e-12;
|
|
7528
7536
|
|
|
7529
7537
|
// Create a smooth facet projection from any radial azimuthal projection.
|
|
7530
7538
|
// The azimuthal coordinates are warped back to the gnomonic polygon along
|
|
@@ -7534,7 +7542,7 @@
|
|
|
7534
7542
|
var center = options.planarCenter || getSphericalCenter(coords);
|
|
7535
7543
|
var gnomonic = createGnomonicProjector(center);
|
|
7536
7544
|
var planar = coords.map(function(p) {
|
|
7537
|
-
return gnomonic(p[0] * D2R$
|
|
7545
|
+
return gnomonic(p[0] * D2R$4, p[1] * D2R$4);
|
|
7538
7546
|
});
|
|
7539
7547
|
var edges = createNormalizedEdges(planar);
|
|
7540
7548
|
var radial = createRadialFunction(
|
|
@@ -7553,7 +7561,7 @@
|
|
|
7553
7561
|
function project(lam, phi) {
|
|
7554
7562
|
var p = gnomonic(lam, phi);
|
|
7555
7563
|
var r = Math.hypot(p[0], p[1]);
|
|
7556
|
-
if (r < EPS) return [0, 0];
|
|
7564
|
+
if (r < EPS$2) return [0, 0];
|
|
7557
7565
|
var c = Math.atan(r);
|
|
7558
7566
|
var azimuthalRadius = radial(c) * radialScale;
|
|
7559
7567
|
var boundaryWeight = getBoundaryWeight(p, edges, boundaryStrength);
|
|
@@ -7643,8 +7651,8 @@
|
|
|
7643
7651
|
|
|
7644
7652
|
function getSphericalCenter(coords) {
|
|
7645
7653
|
var sum = coords.reduce(function(memo, p) {
|
|
7646
|
-
var lam = p[0] * D2R$
|
|
7647
|
-
var phi = p[1] * D2R$
|
|
7654
|
+
var lam = p[0] * D2R$4;
|
|
7655
|
+
var phi = p[1] * D2R$4;
|
|
7648
7656
|
var cosPhi = Math.cos(phi);
|
|
7649
7657
|
memo[0] += Math.cos(lam) * cosPhi;
|
|
7650
7658
|
memo[1] += Math.sin(lam) * cosPhi;
|
|
@@ -7652,8 +7660,8 @@
|
|
|
7652
7660
|
return memo;
|
|
7653
7661
|
}, [0, 0, 0]);
|
|
7654
7662
|
return [
|
|
7655
|
-
Math.atan2(sum[1], sum[0]) / D2R$
|
|
7656
|
-
Math.atan2(sum[2], Math.hypot(sum[0], sum[1])) / D2R$
|
|
7663
|
+
Math.atan2(sum[1], sum[0]) / D2R$4,
|
|
7664
|
+
Math.atan2(sum[2], Math.hypot(sum[0], sum[1])) / D2R$4
|
|
7657
7665
|
];
|
|
7658
7666
|
}
|
|
7659
7667
|
|
|
@@ -7668,8 +7676,8 @@
|
|
|
7668
7676
|
*/
|
|
7669
7677
|
|
|
7670
7678
|
|
|
7671
|
-
var D2R$
|
|
7672
|
-
var R2D$
|
|
7679
|
+
var D2R$3 = Math.PI / 180;
|
|
7680
|
+
var R2D$3 = 180 / Math.PI;
|
|
7673
7681
|
var RADIAL_BOUNDARY_STRENGTH = 1;
|
|
7674
7682
|
var OCTAHEDRON = createOctahedron();
|
|
7675
7683
|
var BUTTERFLY_PARENTS = [-1, 0, 0, 1, 0, 1, 4, 5];
|
|
@@ -7678,7 +7686,7 @@
|
|
|
7678
7686
|
butterfly2: -20,
|
|
7679
7687
|
cahill_keyes: -20
|
|
7680
7688
|
};
|
|
7681
|
-
var engines = {};
|
|
7689
|
+
var engines$2 = {};
|
|
7682
7690
|
|
|
7683
7691
|
function registerButterflyProjections(mproj) {
|
|
7684
7692
|
if (!mproj) return;
|
|
@@ -7696,22 +7704,22 @@
|
|
|
7696
7704
|
|
|
7697
7705
|
function getButterflyEngine(method) {
|
|
7698
7706
|
var key = method == 'butterfly2' ? 'butterfly' : method;
|
|
7699
|
-
if (!engines[key]) {
|
|
7707
|
+
if (!engines$2[key]) {
|
|
7700
7708
|
if (key == 'cahill_keyes') {
|
|
7701
|
-
engines[key] = createCahillKeyesEngine();
|
|
7709
|
+
engines$2[key] = createCahillKeyesEngine();
|
|
7702
7710
|
} else if (key == 'butterfly') {
|
|
7703
|
-
engines[key] = createButterflyEngine();
|
|
7711
|
+
engines$2[key] = createButterflyEngine();
|
|
7704
7712
|
} else {
|
|
7705
7713
|
throw new Error('Unknown butterfly projection: ' + method);
|
|
7706
7714
|
}
|
|
7707
7715
|
}
|
|
7708
|
-
return engines[key];
|
|
7716
|
+
return engines$2[key];
|
|
7709
7717
|
}
|
|
7710
7718
|
|
|
7711
7719
|
function initButterfly(P, method) {
|
|
7712
7720
|
var engine = getButterflyEngine(method);
|
|
7713
7721
|
if (!P.params.lon_0) {
|
|
7714
|
-
P.lam0 = DEFAULT_LON0[method] * D2R$
|
|
7722
|
+
P.lam0 = DEFAULT_LON0[method] * D2R$3;
|
|
7715
7723
|
}
|
|
7716
7724
|
P.es = 0;
|
|
7717
7725
|
P.inv = null;
|
|
@@ -7724,7 +7732,7 @@
|
|
|
7724
7732
|
xy.y = p[1];
|
|
7725
7733
|
}
|
|
7726
7734
|
};
|
|
7727
|
-
P.__projection_topology = engine.getTopology(P.lam0 * R2D$
|
|
7735
|
+
P.__projection_topology = engine.getTopology(P.lam0 * R2D$3);
|
|
7728
7736
|
if (engine.removeOutlineExtremeConnectors) {
|
|
7729
7737
|
P.__remove_outline_extreme_connectors = true;
|
|
7730
7738
|
}
|
|
@@ -7738,8 +7746,8 @@
|
|
|
7738
7746
|
// Reuse the Cahill-Keyes polar incisions and 12-zone octant transform,
|
|
7739
7747
|
// then unfold the faces with the butterfly attachment tree.
|
|
7740
7748
|
var data = createTruncatedOctahedronFaces(
|
|
7741
|
-
Math.cos(17 * D2R$
|
|
7742
|
-
Math.sin(17 * D2R$
|
|
7749
|
+
Math.cos(17 * D2R$3),
|
|
7750
|
+
Math.sin(17 * D2R$3),
|
|
7743
7751
|
BUTTERFLY_PARENTS
|
|
7744
7752
|
);
|
|
7745
7753
|
var faceRaw = createCahillKeyesFaceRaw(10000);
|
|
@@ -7752,9 +7760,9 @@
|
|
|
7752
7760
|
findFace: createTruncatedFaceFinder(data.cornerNormals),
|
|
7753
7761
|
faceProjector: function(face) {
|
|
7754
7762
|
var baseId = face.id < 8 ? face.id : data.parents[face.id];
|
|
7755
|
-
var center = faceCenters[baseId] * D2R$
|
|
7763
|
+
var center = faceCenters[baseId] * D2R$3;
|
|
7756
7764
|
var raw = function(lam, phi) {
|
|
7757
|
-
return faceRaw(normalizeRadians(lam - center), phi);
|
|
7765
|
+
return faceRaw(normalizeRadians$1(lam - center), phi);
|
|
7758
7766
|
};
|
|
7759
7767
|
return createNormalizedFacetProjector(face.coords, raw);
|
|
7760
7768
|
}
|
|
@@ -7767,7 +7775,7 @@
|
|
|
7767
7775
|
// Remove the global placement and scale of a raw facet while preserving its
|
|
7768
7776
|
// internal shape. The polyhedral engine then controls how facets unfold.
|
|
7769
7777
|
var points = coords.map(function(p) {
|
|
7770
|
-
return raw(p[0] * D2R$
|
|
7778
|
+
return raw(p[0] * D2R$3, p[1] * D2R$3);
|
|
7771
7779
|
});
|
|
7772
7780
|
var edge = 0;
|
|
7773
7781
|
var maxLengthSq = -1;
|
|
@@ -7856,8 +7864,8 @@
|
|
|
7856
7864
|
|
|
7857
7865
|
function createCahillKeyesEngine() {
|
|
7858
7866
|
var data = createTruncatedOctahedronFaces(
|
|
7859
|
-
Math.cos(17 * D2R$
|
|
7860
|
-
Math.sin(17 * D2R$
|
|
7867
|
+
Math.cos(17 * D2R$3),
|
|
7868
|
+
Math.sin(17 * D2R$3),
|
|
7861
7869
|
[-1, 3, 0, 2, 0, 1, 4, 5]
|
|
7862
7870
|
);
|
|
7863
7871
|
var raw = createCahillKeyesRaw(10000);
|
|
@@ -7898,10 +7906,10 @@
|
|
|
7898
7906
|
var a = vectors[vectors.length - 1];
|
|
7899
7907
|
vectors.forEach(function(b) {
|
|
7900
7908
|
hexagon.push(
|
|
7901
|
-
vectorToDegrees(normalizeVector(addScaledVectors(
|
|
7909
|
+
vectorToDegrees(normalizeVector$1(addScaledVectors(
|
|
7902
7910
|
a, edgeWeight, b, vertexWeight
|
|
7903
7911
|
))),
|
|
7904
|
-
vectorToDegrees(normalizeVector(addScaledVectors(
|
|
7912
|
+
vectorToDegrees(normalizeVector$1(addScaledVectors(
|
|
7905
7913
|
b, edgeWeight, a, vertexWeight
|
|
7906
7914
|
)))
|
|
7907
7915
|
);
|
|
@@ -8002,7 +8010,7 @@
|
|
|
8002
8010
|
}
|
|
8003
8011
|
|
|
8004
8012
|
function planarAngle(p, project) {
|
|
8005
|
-
var q = project(p[0] * D2R$
|
|
8013
|
+
var q = project(p[0] * D2R$3, p[1] * D2R$3);
|
|
8006
8014
|
return Math.atan2(q[1], q[0]);
|
|
8007
8015
|
}
|
|
8008
8016
|
|
|
@@ -8036,16 +8044,16 @@
|
|
|
8036
8044
|
}
|
|
8037
8045
|
|
|
8038
8046
|
function degreesToVector(p) {
|
|
8039
|
-
var lam = p[0] * D2R$
|
|
8040
|
-
var phi = p[1] * D2R$
|
|
8047
|
+
var lam = p[0] * D2R$3;
|
|
8048
|
+
var phi = p[1] * D2R$3;
|
|
8041
8049
|
var cosPhi = Math.cos(phi);
|
|
8042
8050
|
return [Math.cos(lam) * cosPhi, Math.sin(lam) * cosPhi, Math.sin(phi)];
|
|
8043
8051
|
}
|
|
8044
8052
|
|
|
8045
8053
|
function vectorToDegrees(p) {
|
|
8046
8054
|
return [
|
|
8047
|
-
Math.atan2(p[1], p[0]) * R2D$
|
|
8048
|
-
Math.asin(Math.max(-1, Math.min(1, p[2]))) * R2D$
|
|
8055
|
+
Math.atan2(p[1], p[0]) * R2D$3,
|
|
8056
|
+
Math.asin(Math.max(-1, Math.min(1, p[2]))) * R2D$3
|
|
8049
8057
|
];
|
|
8050
8058
|
}
|
|
8051
8059
|
|
|
@@ -8069,12 +8077,12 @@
|
|
|
8069
8077
|
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
8070
8078
|
}
|
|
8071
8079
|
|
|
8072
|
-
function normalizeVector(p) {
|
|
8080
|
+
function normalizeVector$1(p) {
|
|
8073
8081
|
var k = 1 / Math.sqrt(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]);
|
|
8074
8082
|
return [p[0] * k, p[1] * k, p[2] * k];
|
|
8075
8083
|
}
|
|
8076
8084
|
|
|
8077
|
-
function normalizeRadians(lam) {
|
|
8085
|
+
function normalizeRadians$1(lam) {
|
|
8078
8086
|
return (lam + Math.PI * 3) % (Math.PI * 2) - Math.PI;
|
|
8079
8087
|
}
|
|
8080
8088
|
|
|
@@ -8085,9 +8093,1460 @@
|
|
|
8085
8093
|
registerButterflyProjections: registerButterflyProjections
|
|
8086
8094
|
});
|
|
8087
8095
|
|
|
8096
|
+
/*
|
|
8097
|
+
* Forward implementation of Hajime Narukawa's 2022 mathematical
|
|
8098
|
+
* approximation of the AuthaGraph construction.
|
|
8099
|
+
*
|
|
8100
|
+
* Facet formula:
|
|
8101
|
+
* H. Narukawa, "Formulation of AuthaGraph Map Projection" (2022)
|
|
8102
|
+
* https://www.jstage.jst.go.jp/article/jjca/60/1/60_1/_article/-char/en
|
|
8103
|
+
*
|
|
8104
|
+
* The rectangular facet routing follows the public Imago arrangement by
|
|
8105
|
+
* Justin Kunimune. The face transform itself uses Narukawa's published
|
|
8106
|
+
* equations, not Imago's power-law approximation.
|
|
8107
|
+
*/
|
|
8108
|
+
|
|
8109
|
+
var D2R$2 = Math.PI / 180;
|
|
8110
|
+
var R2D$2 = 180 / Math.PI;
|
|
8111
|
+
var HALF_PI = Math.PI / 2;
|
|
8112
|
+
var SQRT2$1 = Math.sqrt(2);
|
|
8113
|
+
var SQRT3$1 = Math.sqrt(3);
|
|
8114
|
+
var ASIN_ONE_THIRD$1 = Math.asin(1 / 3);
|
|
8115
|
+
var EDGE_SCALE = Math.acos(-1 / 3) / 2;
|
|
8116
|
+
var XMIN = -2 * SQRT3$1;
|
|
8117
|
+
var XMAX = 2 * SQRT3$1;
|
|
8118
|
+
var YMIN = -1.5;
|
|
8119
|
+
var YMAX = 1.5;
|
|
8120
|
+
var BLOCK_HEIGHT = 2 * SQRT3$1;
|
|
8121
|
+
var LAYOUT_SHIFT = 1.16;
|
|
8122
|
+
var EPS$1 = 1e-12;
|
|
8123
|
+
var engines$1 = {};
|
|
8124
|
+
|
|
8125
|
+
// The four tetrahedron vertices published by Narukawa, in latitude-longitude
|
|
8126
|
+
// order. The extra precision preserves the regular tetrahedron to about 1e-9
|
|
8127
|
+
// in vector dot products.
|
|
8128
|
+
var GEOGRAPHIC_VERTICES = [
|
|
8129
|
+
[76.8810628, 149.4509913],
|
|
8130
|
+
[-27.9527772, 97.3570035],
|
|
8131
|
+
[-6.6370473, -18.8522325],
|
|
8132
|
+
[-22.9282364, -133.2827588]
|
|
8133
|
+
];
|
|
8134
|
+
|
|
8135
|
+
// D3 Imago's vertex-oriented tetrahedral block. Each entry contains the
|
|
8136
|
+
// spherical center, local meridian, planar rotation and planar center.
|
|
8137
|
+
var FACET_DEFS = [
|
|
8138
|
+
[0, SQRT3$1, HALF_PI, 0, 0, -HALF_PI],
|
|
8139
|
+
[0, -SQRT3$1, -ASIN_ONE_THIRD$1, 0, Math.PI, HALF_PI],
|
|
8140
|
+
[3, 0, -ASIN_ONE_THIRD$1, 2 * Math.PI / 3, Math.PI, 5 * Math.PI / 6],
|
|
8141
|
+
[-3, 0, -ASIN_ONE_THIRD$1, -2 * Math.PI / 3, Math.PI, Math.PI / 6]
|
|
8142
|
+
];
|
|
8143
|
+
|
|
8144
|
+
function registerNarukawa2022Projection(mproj) {
|
|
8145
|
+
if (!mproj || mproj.internal.pj_list.narukawa2022) return;
|
|
8146
|
+
mproj.pj_add(function(P) {
|
|
8147
|
+
initNarukawa2022(P);
|
|
8148
|
+
}, 'narukawa2022', 'Narukawa 2022 tetrahedral world map');
|
|
8149
|
+
}
|
|
8150
|
+
|
|
8151
|
+
function getNarukawa2022Engine() {
|
|
8152
|
+
if (!engines$1.default) {
|
|
8153
|
+
engines$1.default = createNarukawa2022Engine();
|
|
8154
|
+
}
|
|
8155
|
+
return engines$1.default;
|
|
8156
|
+
}
|
|
8157
|
+
|
|
8158
|
+
function initNarukawa2022(P) {
|
|
8159
|
+
var engine = getNarukawa2022Engine();
|
|
8160
|
+
P.es = 0;
|
|
8161
|
+
P.inv = null;
|
|
8162
|
+
P.fwd = function(lp, xy) {
|
|
8163
|
+
var p = engine.forward(lp.lam, lp.phi);
|
|
8164
|
+
xy.x = p[0];
|
|
8165
|
+
xy.y = p[1];
|
|
8166
|
+
};
|
|
8167
|
+
P.__projection_topology = engine.getTopology(P.lam0 * R2D$2);
|
|
8168
|
+
P.__projected_outline = engine.outline;
|
|
8169
|
+
}
|
|
8170
|
+
|
|
8171
|
+
function createNarukawa2022Engine() {
|
|
8172
|
+
var orientation = createPublishedOrientation();
|
|
8173
|
+
var facets = FACET_DEFS.map(function(def, i) {
|
|
8174
|
+
return {
|
|
8175
|
+
id: i,
|
|
8176
|
+
x: def[0],
|
|
8177
|
+
y: def[1],
|
|
8178
|
+
lat: def[2],
|
|
8179
|
+
lon: def[3],
|
|
8180
|
+
meridian: def[4],
|
|
8181
|
+
rotation: def[5]
|
|
8182
|
+
};
|
|
8183
|
+
});
|
|
8184
|
+
var rasterSectors = facets.reduce(function(memo, facet) {
|
|
8185
|
+
return memo.concat(getRawFacetSectorBoundaries(facets, facet));
|
|
8186
|
+
}, []);
|
|
8187
|
+
var rasterPieces = createNarukawaRasterPieces(facets, rasterSectors);
|
|
8188
|
+
var rasterPieceIndex = new Map(rasterPieces.map(function(piece) {
|
|
8189
|
+
return [piece.key, piece.id];
|
|
8190
|
+
}));
|
|
8191
|
+
var outline = [[
|
|
8192
|
+
[XMIN * EDGE_SCALE, YMIN * EDGE_SCALE],
|
|
8193
|
+
[XMAX * EDGE_SCALE, YMIN * EDGE_SCALE],
|
|
8194
|
+
[XMAX * EDGE_SCALE, YMAX * EDGE_SCALE],
|
|
8195
|
+
[XMIN * EDGE_SCALE, YMAX * EDGE_SCALE],
|
|
8196
|
+
[XMIN * EDGE_SCALE, YMIN * EDGE_SCALE]
|
|
8197
|
+
]];
|
|
8198
|
+
|
|
8199
|
+
return {
|
|
8200
|
+
forward: forward,
|
|
8201
|
+
inverse: inverse,
|
|
8202
|
+
outline: outline,
|
|
8203
|
+
rasterPieces: rasterPieces,
|
|
8204
|
+
getTopology: getTopology
|
|
8205
|
+
};
|
|
8206
|
+
|
|
8207
|
+
function forward(lam, phi) {
|
|
8208
|
+
var state = projectState(lam, phi);
|
|
8209
|
+
return [state.x * EDGE_SCALE, state.y * EDGE_SCALE];
|
|
8210
|
+
}
|
|
8211
|
+
|
|
8212
|
+
// Internal inverse used only for tracing the geographic rectangular cut.
|
|
8213
|
+
// P.inv remains null because the full Mapshaper inverse path is unsupported.
|
|
8214
|
+
function inverse(x, y) {
|
|
8215
|
+
var p = invertLayout(x / EDGE_SCALE, y / EDGE_SCALE, facets);
|
|
8216
|
+
if (!p) return null;
|
|
8217
|
+
return fromCanonical(p[0], p[1], orientation);
|
|
8218
|
+
}
|
|
8219
|
+
|
|
8220
|
+
function projectState(lam, phi) {
|
|
8221
|
+
var p = toCanonical(lam, phi, orientation);
|
|
8222
|
+
var state = projectCanonical(p[0], p[1], facets);
|
|
8223
|
+
state.region = encodeRegion(state);
|
|
8224
|
+
return state;
|
|
8225
|
+
}
|
|
8226
|
+
|
|
8227
|
+
function getTopology(lon0) {
|
|
8228
|
+
var paths = createCutPaths(inverse, lon0);
|
|
8229
|
+
return {
|
|
8230
|
+
regions: createRegionIndex(),
|
|
8231
|
+
seams: [{
|
|
8232
|
+
type: 'cut',
|
|
8233
|
+
paths: paths
|
|
8234
|
+
}],
|
|
8235
|
+
findRegion: findRegion,
|
|
8236
|
+
findTransitionRegion: findRegion,
|
|
8237
|
+
raster_regions: rasterPieces.map(function(piece) {
|
|
8238
|
+
return {
|
|
8239
|
+
id: piece.id,
|
|
8240
|
+
facet: piece.facet,
|
|
8241
|
+
sector: piece.sector,
|
|
8242
|
+
source_region: piece.facet * 3 + piece.sector,
|
|
8243
|
+
projected_boundary: piece.boundary.map(function(p) {
|
|
8244
|
+
return [p[0] * EDGE_SCALE, p[1] * EDGE_SCALE];
|
|
8245
|
+
})
|
|
8246
|
+
};
|
|
8247
|
+
}),
|
|
8248
|
+
raster_source_regions: rasterSectors.map(function(sector) {
|
|
8249
|
+
return {
|
|
8250
|
+
id: sector.facet * 3 + sector.sector,
|
|
8251
|
+
source_region: sector.facet * 3 + sector.sector,
|
|
8252
|
+
facet: sector.facet,
|
|
8253
|
+
sector: sector.sector,
|
|
8254
|
+
boundary: sector.sphericalBoundary.map(function(p) {
|
|
8255
|
+
var q = fromCanonical(p[0], p[1], orientation);
|
|
8256
|
+
return [
|
|
8257
|
+
normalizeLongitude$2(q[0] * R2D$2 + lon0),
|
|
8258
|
+
q[1] * R2D$2
|
|
8259
|
+
];
|
|
8260
|
+
})
|
|
8261
|
+
};
|
|
8262
|
+
}),
|
|
8263
|
+
raster_mesh_interval: 32,
|
|
8264
|
+
raster_cell_halo: false,
|
|
8265
|
+
fill_raster_mask: true,
|
|
8266
|
+
fill_raster_coverage: true,
|
|
8267
|
+
findRasterRegion: findRasterRegion,
|
|
8268
|
+
projectRasterRegion: projectRasterRegion,
|
|
8269
|
+
projectRasterSourceRegion: projectRasterSourceRegion,
|
|
8270
|
+
projectRasterSector: projectRasterSector,
|
|
8271
|
+
clipRasterRegionPolygon: clipRasterRegionPolygon,
|
|
8272
|
+
outline: outline.map(function(ring) {
|
|
8273
|
+
return ring.map(function(p) {
|
|
8274
|
+
return p.concat();
|
|
8275
|
+
});
|
|
8276
|
+
})
|
|
8277
|
+
};
|
|
8278
|
+
|
|
8279
|
+
function findRegion(lon, lat) {
|
|
8280
|
+
var lam = normalizeRadians((lon - lon0) * D2R$2);
|
|
8281
|
+
return projectState(lam, lat * D2R$2).region;
|
|
8282
|
+
}
|
|
8283
|
+
|
|
8284
|
+
function findRasterRegion(lon, lat) {
|
|
8285
|
+
var lam = normalizeRadians((lon - lon0) * D2R$2);
|
|
8286
|
+
var p = toCanonical(lam, lat * D2R$2, orientation);
|
|
8287
|
+
var facet = findForwardFacet(p[0], p[1], facets);
|
|
8288
|
+
var state = applyConditionalLayout(projectFacetRaw(p[0], p[1], facet), facet);
|
|
8289
|
+
return rasterPieceIndex.get(getRasterPieceKey(
|
|
8290
|
+
state.facet, state.sector, state.oobKey, state.folded, state.wrap
|
|
8291
|
+
));
|
|
8292
|
+
}
|
|
8293
|
+
|
|
8294
|
+
function projectRasterRegion(lon, lat, regionId) {
|
|
8295
|
+
var piece = rasterPieces[regionId];
|
|
8296
|
+
var lam = normalizeRadians((lon - lon0) * D2R$2);
|
|
8297
|
+
var p = toCanonical(lam, lat * D2R$2, orientation);
|
|
8298
|
+
var facet = facets[piece.facet];
|
|
8299
|
+
var raw = projectFacetRaw(p[0], p[1], facet, piece.sector);
|
|
8300
|
+
var q = applyRasterPieceLayout(raw, facet, piece);
|
|
8301
|
+
return [q[0] * EDGE_SCALE, q[1] * EDGE_SCALE];
|
|
8302
|
+
}
|
|
8303
|
+
|
|
8304
|
+
function projectRasterSector(lon, lat, facetId, sector) {
|
|
8305
|
+
var lam = normalizeRadians((lon - lon0) * D2R$2);
|
|
8306
|
+
var p = toCanonical(lam, lat * D2R$2, orientation);
|
|
8307
|
+
var raw = projectFacetRaw(p[0], p[1], facets[facetId], sector);
|
|
8308
|
+
return [raw.x, raw.y];
|
|
8309
|
+
}
|
|
8310
|
+
|
|
8311
|
+
function projectRasterSourceRegion(lon, lat, sourceRegionId) {
|
|
8312
|
+
return projectRasterSector(
|
|
8313
|
+
lon, lat, Math.floor(sourceRegionId / 3), sourceRegionId % 3);
|
|
8314
|
+
}
|
|
8315
|
+
|
|
8316
|
+
function clipRasterRegionPolygon(vertices, regionId) {
|
|
8317
|
+
return clipRasterPiecePolygon(
|
|
8318
|
+
vertices, facets[rasterPieces[regionId].facet],
|
|
8319
|
+
rasterPieces[regionId]);
|
|
8320
|
+
}
|
|
8321
|
+
}
|
|
8322
|
+
}
|
|
8323
|
+
|
|
8324
|
+
function createNarukawaRasterPieces(facets, rasterSectors) {
|
|
8325
|
+
var pieces = [];
|
|
8326
|
+
facets.forEach(function(facet) {
|
|
8327
|
+
rasterSectors.filter(function(o) {
|
|
8328
|
+
return o.facet == facet.id;
|
|
8329
|
+
}).forEach(function(sectorData) {
|
|
8330
|
+
['normal', 'xpos', 'xneg', 'ypos', 'yneg'].forEach(function(oobKey) {
|
|
8331
|
+
var oobPolygon = clipOobPolygon(sectorData.boundary, oobKey);
|
|
8332
|
+
if (oobPolygon.length < 3) return;
|
|
8333
|
+
oobPolygon = oobPolygon.map(function(p) {
|
|
8334
|
+
return applyOobTransform(p, facet, oobKey);
|
|
8335
|
+
});
|
|
8336
|
+
[0, 1].forEach(function(folded) {
|
|
8337
|
+
var foldedPolygon = clipPolygonAxis$1(oobPolygon, 0, 0, folded == 0);
|
|
8338
|
+
if (foldedPolygon.length < 3) return;
|
|
8339
|
+
foldedPolygon = foldedPolygon.map(function(p) {
|
|
8340
|
+
return applyFoldTransform(p, folded);
|
|
8341
|
+
});
|
|
8342
|
+
[0, 1].forEach(function(wrap) {
|
|
8343
|
+
var finalPolygon = foldedPolygon.map(function(p) {
|
|
8344
|
+
return [
|
|
8345
|
+
p[0] + LAYOUT_SHIFT + wrap * 2 * BLOCK_HEIGHT - BLOCK_HEIGHT,
|
|
8346
|
+
p[1] + 1.5
|
|
8347
|
+
];
|
|
8348
|
+
});
|
|
8349
|
+
finalPolygon = clipRectangle(
|
|
8350
|
+
finalPolygon, XMIN, YMIN, XMAX, YMAX);
|
|
8351
|
+
if (finalPolygon.length < 3 ||
|
|
8352
|
+
Math.abs(getPlanarRingArea(finalPolygon)) < EPS$1) return;
|
|
8353
|
+
var id = pieces.length;
|
|
8354
|
+
pieces.push({
|
|
8355
|
+
id: id,
|
|
8356
|
+
key: getRasterPieceKey(
|
|
8357
|
+
facet.id, sectorData.sector, oobKey, folded, wrap),
|
|
8358
|
+
facet: facet.id,
|
|
8359
|
+
sector: sectorData.sector,
|
|
8360
|
+
oobKey: oobKey,
|
|
8361
|
+
folded: folded,
|
|
8362
|
+
wrap: wrap,
|
|
8363
|
+
boundary: finalPolygon.concat([finalPolygon[0].concat()])
|
|
8364
|
+
});
|
|
8365
|
+
});
|
|
8366
|
+
});
|
|
8367
|
+
});
|
|
8368
|
+
});
|
|
8369
|
+
});
|
|
8370
|
+
return pieces;
|
|
8371
|
+
}
|
|
8372
|
+
|
|
8373
|
+
function getRawFacetSectorBoundaries(facets, facet) {
|
|
8374
|
+
var corners = facets.filter(function(o) {
|
|
8375
|
+
return o.id != facet.id;
|
|
8376
|
+
}).map(function(o) {
|
|
8377
|
+
var v = radiansToVector(o.lon, o.lat);
|
|
8378
|
+
return vectorToRadians([-v[0], -v[1], -v[2]]);
|
|
8379
|
+
});
|
|
8380
|
+
corners.sort(function(a, b) {
|
|
8381
|
+
return obliquifySpherical(a[1], a[0], facet)[1] -
|
|
8382
|
+
obliquifySpherical(b[1], b[0], facet)[1];
|
|
8383
|
+
});
|
|
8384
|
+
var samples = [];
|
|
8385
|
+
for (var i = 0; i < corners.length; i++) {
|
|
8386
|
+
var edge = interpolateSphericalRadians(
|
|
8387
|
+
corners[i], corners[(i + 1) % corners.length], 0.05 * D2R$2);
|
|
8388
|
+
for (var j = 0; j < edge.length - 1; j++) {
|
|
8389
|
+
var p = edge[j];
|
|
8390
|
+
var q = projectFacetRaw(p[0], p[1], facet);
|
|
8391
|
+
samples.push({
|
|
8392
|
+
sector: q.sector,
|
|
8393
|
+
point: [q.x, q.y],
|
|
8394
|
+
spherical: p.concat()
|
|
8395
|
+
});
|
|
8396
|
+
}
|
|
8397
|
+
}
|
|
8398
|
+
return [0, 1, 2].map(function(sector) {
|
|
8399
|
+
var run = getLongestCircularSectorRun(samples, sector);
|
|
8400
|
+
var middle = getFarthestSphericalSample(
|
|
8401
|
+
run, [facet.lon, facet.lat]);
|
|
8402
|
+
return {
|
|
8403
|
+
facet: facet.id,
|
|
8404
|
+
sector: sector,
|
|
8405
|
+
sphericalBoundary: [
|
|
8406
|
+
[facet.lon, facet.lat],
|
|
8407
|
+
run[0].spherical,
|
|
8408
|
+
middle.spherical,
|
|
8409
|
+
run[run.length - 1].spherical,
|
|
8410
|
+
[facet.lon, facet.lat]
|
|
8411
|
+
],
|
|
8412
|
+
boundary: [[facet.x, facet.y]].concat(run.map(function(o) {
|
|
8413
|
+
return o.point;
|
|
8414
|
+
}))
|
|
8415
|
+
};
|
|
8416
|
+
});
|
|
8417
|
+
}
|
|
8418
|
+
|
|
8419
|
+
function getFarthestSphericalSample(samples, center) {
|
|
8420
|
+
var centerVector = radiansToVector(center[0], center[1]);
|
|
8421
|
+
var best = samples[0];
|
|
8422
|
+
var minDot = Infinity;
|
|
8423
|
+
samples.forEach(function(sample) {
|
|
8424
|
+
var v = radiansToVector(sample.spherical[0], sample.spherical[1]);
|
|
8425
|
+
var d = dot$1(centerVector, v);
|
|
8426
|
+
if (d < minDot) {
|
|
8427
|
+
minDot = d;
|
|
8428
|
+
best = sample;
|
|
8429
|
+
}
|
|
8430
|
+
});
|
|
8431
|
+
return best;
|
|
8432
|
+
}
|
|
8433
|
+
|
|
8434
|
+
function getLongestCircularSectorRun(samples, sector) {
|
|
8435
|
+
var runs = [];
|
|
8436
|
+
var run = [];
|
|
8437
|
+
for (var i = 0; i < samples.length * 2; i++) {
|
|
8438
|
+
var sample = samples[i % samples.length];
|
|
8439
|
+
if (sample.sector == sector) {
|
|
8440
|
+
run.push(sample);
|
|
8441
|
+
} else if (run.length) {
|
|
8442
|
+
runs.push(run);
|
|
8443
|
+
run = [];
|
|
8444
|
+
}
|
|
8445
|
+
}
|
|
8446
|
+
if (run.length) runs.push(run);
|
|
8447
|
+
runs.sort(function(a, b) { return b.length - a.length; });
|
|
8448
|
+
run = runs[0] || [];
|
|
8449
|
+
if (run.length > samples.length) run = run.slice(0, samples.length);
|
|
8450
|
+
return run;
|
|
8451
|
+
}
|
|
8452
|
+
|
|
8453
|
+
function applyRasterPieceLayout(raw, facet, piece) {
|
|
8454
|
+
var p = applyOobTransform([raw.x, raw.y], facet, piece.oobKey);
|
|
8455
|
+
p = applyFoldTransform(p, piece.folded);
|
|
8456
|
+
return [
|
|
8457
|
+
p[0] + LAYOUT_SHIFT + piece.wrap * 2 * BLOCK_HEIGHT - BLOCK_HEIGHT,
|
|
8458
|
+
p[1] + 1.5
|
|
8459
|
+
];
|
|
8460
|
+
}
|
|
8461
|
+
|
|
8462
|
+
function clipRasterPiecePolygon(vertices, facet, piece) {
|
|
8463
|
+
var polygon = clipRasterOobPolygon(vertices, piece.oobKey);
|
|
8464
|
+
polygon = polygon.map(function(vertex) {
|
|
8465
|
+
var p = applyOobTransform([vertex.x, vertex.y], facet, piece.oobKey);
|
|
8466
|
+
return copyRasterVertex$1(vertex, p[0], p[1]);
|
|
8467
|
+
});
|
|
8468
|
+
polygon = clipRasterPolygonAxis$1(
|
|
8469
|
+
polygon, 'x', 0, piece.folded == 0);
|
|
8470
|
+
polygon = polygon.map(function(vertex) {
|
|
8471
|
+
var p = applyFoldTransform([vertex.x, vertex.y], piece.folded);
|
|
8472
|
+
return copyRasterVertex$1(vertex, p[0], p[1]);
|
|
8473
|
+
});
|
|
8474
|
+
polygon = polygon.map(function(vertex) {
|
|
8475
|
+
return copyRasterVertex$1(
|
|
8476
|
+
vertex,
|
|
8477
|
+
vertex.x + LAYOUT_SHIFT +
|
|
8478
|
+
piece.wrap * 2 * BLOCK_HEIGHT - BLOCK_HEIGHT,
|
|
8479
|
+
vertex.y + 1.5
|
|
8480
|
+
);
|
|
8481
|
+
});
|
|
8482
|
+
polygon = clipRasterPolygonAxis$1(polygon, 'x', XMIN, true);
|
|
8483
|
+
polygon = clipRasterPolygonAxis$1(polygon, 'x', XMAX, false);
|
|
8484
|
+
polygon = clipRasterPolygonAxis$1(polygon, 'y', YMIN, true);
|
|
8485
|
+
polygon = clipRasterPolygonAxis$1(polygon, 'y', YMAX, false);
|
|
8486
|
+
polygon.forEach(function(vertex) {
|
|
8487
|
+
vertex.x *= EDGE_SCALE;
|
|
8488
|
+
vertex.y *= EDGE_SCALE;
|
|
8489
|
+
});
|
|
8490
|
+
return polygon;
|
|
8491
|
+
}
|
|
8492
|
+
|
|
8493
|
+
function clipRasterOobPolygon(polygon, oobKey) {
|
|
8494
|
+
if (oobKey == 'xpos') {
|
|
8495
|
+
return clipRasterPolygonAxis$1(polygon, 'x', 3, true);
|
|
8496
|
+
}
|
|
8497
|
+
if (oobKey == 'xneg') {
|
|
8498
|
+
return clipRasterPolygonAxis$1(polygon, 'x', -3, false);
|
|
8499
|
+
}
|
|
8500
|
+
if (oobKey == 'ypos' || oobKey == 'yneg') {
|
|
8501
|
+
polygon = clipRasterPolygonAxis$1(polygon, 'x', -3, true);
|
|
8502
|
+
polygon = clipRasterPolygonAxis$1(polygon, 'x', 3, false);
|
|
8503
|
+
return clipRasterPolygonAxis$1(
|
|
8504
|
+
polygon, 'y', oobKey == 'ypos' ? SQRT3$1 : -SQRT3$1,
|
|
8505
|
+
oobKey == 'ypos');
|
|
8506
|
+
}
|
|
8507
|
+
polygon = clipRasterPolygonAxis$1(polygon, 'x', -3, true);
|
|
8508
|
+
polygon = clipRasterPolygonAxis$1(polygon, 'x', 3, false);
|
|
8509
|
+
polygon = clipRasterPolygonAxis$1(polygon, 'y', -SQRT3$1, true);
|
|
8510
|
+
return clipRasterPolygonAxis$1(polygon, 'y', SQRT3$1, false);
|
|
8511
|
+
}
|
|
8512
|
+
|
|
8513
|
+
function clipRasterPolygonAxis$1(polygon, axis, value, keepGreater) {
|
|
8514
|
+
var output = [];
|
|
8515
|
+
if (polygon.length === 0) return output;
|
|
8516
|
+
var a = polygon[polygon.length - 1];
|
|
8517
|
+
var aInside = keepGreater ?
|
|
8518
|
+
a[axis] >= value - EPS$1 : a[axis] <= value + EPS$1;
|
|
8519
|
+
polygon.forEach(function(b) {
|
|
8520
|
+
var bInside = keepGreater ?
|
|
8521
|
+
b[axis] >= value - EPS$1 : b[axis] <= value + EPS$1;
|
|
8522
|
+
if (aInside != bInside) {
|
|
8523
|
+
var t = (value - a[axis]) / (b[axis] - a[axis]);
|
|
8524
|
+
var vertex = {
|
|
8525
|
+
x: a.x + (b.x - a.x) * t,
|
|
8526
|
+
y: a.y + (b.y - a.y) * t,
|
|
8527
|
+
sx: a.sx + (b.sx - a.sx) * t,
|
|
8528
|
+
sy: a.sy + (b.sy - a.sy) * t,
|
|
8529
|
+
lon: a.lon + (b.lon - a.lon) * t,
|
|
8530
|
+
lat: a.lat + (b.lat - a.lat) * t
|
|
8531
|
+
};
|
|
8532
|
+
vertex[axis] = value;
|
|
8533
|
+
output.push(vertex);
|
|
8534
|
+
}
|
|
8535
|
+
if (bInside) output.push(copyRasterVertex$1(b, b.x, b.y));
|
|
8536
|
+
a = b;
|
|
8537
|
+
aInside = bInside;
|
|
8538
|
+
});
|
|
8539
|
+
return output;
|
|
8540
|
+
}
|
|
8541
|
+
|
|
8542
|
+
function copyRasterVertex$1(vertex, x, y) {
|
|
8543
|
+
return {
|
|
8544
|
+
x: x,
|
|
8545
|
+
y: y,
|
|
8546
|
+
sx: vertex.sx,
|
|
8547
|
+
sy: vertex.sy,
|
|
8548
|
+
lon: vertex.lon,
|
|
8549
|
+
lat: vertex.lat
|
|
8550
|
+
};
|
|
8551
|
+
}
|
|
8552
|
+
|
|
8553
|
+
function applyOobTransform(p, facet, oobKey) {
|
|
8554
|
+
if (oobKey == 'xpos' || oobKey == 'xneg') {
|
|
8555
|
+
return [2 * facet.x - p[0], -p[1]];
|
|
8556
|
+
}
|
|
8557
|
+
if (oobKey == 'ypos') {
|
|
8558
|
+
return [-p[0], BLOCK_HEIGHT - p[1]];
|
|
8559
|
+
}
|
|
8560
|
+
if (oobKey == 'yneg') {
|
|
8561
|
+
return [-p[0], -BLOCK_HEIGHT - p[1]];
|
|
8562
|
+
}
|
|
8563
|
+
return p.concat();
|
|
8564
|
+
}
|
|
8565
|
+
|
|
8566
|
+
function applyFoldTransform(p, folded) {
|
|
8567
|
+
return folded ? [BLOCK_HEIGHT - p[1], p[0]] : [p[1], -p[0]];
|
|
8568
|
+
}
|
|
8569
|
+
|
|
8570
|
+
function clipOobPolygon(polygon, oobKey) {
|
|
8571
|
+
if (oobKey == 'xpos') return clipPolygonAxis$1(polygon, 0, 3, true);
|
|
8572
|
+
if (oobKey == 'xneg') return clipPolygonAxis$1(polygon, 0, -3, false);
|
|
8573
|
+
if (oobKey == 'ypos') {
|
|
8574
|
+
return clipPolygonAxis$1(
|
|
8575
|
+
clipPolygonAxis$1(
|
|
8576
|
+
clipPolygonAxis$1(polygon, 0, -3, true), 0, 3, false),
|
|
8577
|
+
1, SQRT3$1, true);
|
|
8578
|
+
}
|
|
8579
|
+
if (oobKey == 'yneg') {
|
|
8580
|
+
return clipPolygonAxis$1(
|
|
8581
|
+
clipPolygonAxis$1(
|
|
8582
|
+
clipPolygonAxis$1(polygon, 0, -3, true), 0, 3, false),
|
|
8583
|
+
1, -SQRT3$1, false);
|
|
8584
|
+
}
|
|
8585
|
+
return clipRectangle(polygon, -3, -SQRT3$1, 3, SQRT3$1);
|
|
8586
|
+
}
|
|
8587
|
+
|
|
8588
|
+
function clipRectangle(polygon, xmin, ymin, xmax, ymax) {
|
|
8589
|
+
polygon = clipPolygonAxis$1(polygon, 0, xmin, true);
|
|
8590
|
+
polygon = clipPolygonAxis$1(polygon, 0, xmax, false);
|
|
8591
|
+
polygon = clipPolygonAxis$1(polygon, 1, ymin, true);
|
|
8592
|
+
return clipPolygonAxis$1(polygon, 1, ymax, false);
|
|
8593
|
+
}
|
|
8594
|
+
|
|
8595
|
+
function clipPolygonAxis$1(polygon, axis, value, keepGreater) {
|
|
8596
|
+
var output = [];
|
|
8597
|
+
if (polygon.length === 0) return output;
|
|
8598
|
+
var a = polygon[polygon.length - 1];
|
|
8599
|
+
var aInside = keepGreater ? a[axis] >= value - EPS$1 : a[axis] <= value + EPS$1;
|
|
8600
|
+
polygon.forEach(function(b) {
|
|
8601
|
+
var bInside = keepGreater ? b[axis] >= value - EPS$1 : b[axis] <= value + EPS$1;
|
|
8602
|
+
if (aInside != bInside) {
|
|
8603
|
+
var t = (value - a[axis]) / (b[axis] - a[axis]);
|
|
8604
|
+
var p = [
|
|
8605
|
+
a[0] + (b[0] - a[0]) * t,
|
|
8606
|
+
a[1] + (b[1] - a[1]) * t
|
|
8607
|
+
];
|
|
8608
|
+
p[axis] = value;
|
|
8609
|
+
output.push(p);
|
|
8610
|
+
}
|
|
8611
|
+
if (bInside) output.push(b.concat());
|
|
8612
|
+
a = b;
|
|
8613
|
+
aInside = bInside;
|
|
8614
|
+
});
|
|
8615
|
+
return output;
|
|
8616
|
+
}
|
|
8617
|
+
|
|
8618
|
+
function interpolateSphericalRadians(a, b, interval) {
|
|
8619
|
+
var av = radiansToVector(a[0], a[1]);
|
|
8620
|
+
var bv = radiansToVector(b[0], b[1]);
|
|
8621
|
+
var angle = Math.acos(clamp$2(dot$1(av, bv), -1, 1));
|
|
8622
|
+
var count = Math.max(1, Math.ceil(angle / interval));
|
|
8623
|
+
var sinAngle = Math.sin(angle);
|
|
8624
|
+
var points = [];
|
|
8625
|
+
for (var i = 0; i <= count; i++) {
|
|
8626
|
+
var t = i / count;
|
|
8627
|
+
var ka = Math.sin((1 - t) * angle) / sinAngle;
|
|
8628
|
+
var kb = Math.sin(t * angle) / sinAngle;
|
|
8629
|
+
points.push(vectorToRadians(normalizeVector([
|
|
8630
|
+
av[0] * ka + bv[0] * kb,
|
|
8631
|
+
av[1] * ka + bv[1] * kb,
|
|
8632
|
+
av[2] * ka + bv[2] * kb
|
|
8633
|
+
])));
|
|
8634
|
+
}
|
|
8635
|
+
return points;
|
|
8636
|
+
}
|
|
8637
|
+
|
|
8638
|
+
function vectorToRadians(p) {
|
|
8639
|
+
return [
|
|
8640
|
+
Math.atan2(p[1], p[0]),
|
|
8641
|
+
Math.asin(clamp$2(p[2], -1, 1))
|
|
8642
|
+
];
|
|
8643
|
+
}
|
|
8644
|
+
|
|
8645
|
+
function getPlanarRingArea(ring) {
|
|
8646
|
+
var area = 0;
|
|
8647
|
+
for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
8648
|
+
area += ring[j][0] * ring[i][1] - ring[i][0] * ring[j][1];
|
|
8649
|
+
}
|
|
8650
|
+
return area / 2;
|
|
8651
|
+
}
|
|
8652
|
+
|
|
8653
|
+
function getRasterPieceKey(facet, sector, oobKey, folded, wrap) {
|
|
8654
|
+
return [facet, sector, oobKey, folded, wrap].join(':');
|
|
8655
|
+
}
|
|
8656
|
+
|
|
8657
|
+
function projectCanonical(lam, phi, facets) {
|
|
8658
|
+
var facet = findForwardFacet(lam, phi, facets);
|
|
8659
|
+
var state = projectFacetRaw(lam, phi, facet);
|
|
8660
|
+
return applyConditionalLayout(state, facet);
|
|
8661
|
+
}
|
|
8662
|
+
|
|
8663
|
+
function projectFacetRaw(lam, phi, facet, forcedSector) {
|
|
8664
|
+
var relative = obliquifySpherical(phi, lam, facet);
|
|
8665
|
+
var sector = forcedSector == null ?
|
|
8666
|
+
Math.floor((relative[1] + Math.PI / 3) / (2 * Math.PI / 3)) :
|
|
8667
|
+
forcedSector == 2 ? -1 : forcedSector;
|
|
8668
|
+
var base = sector * 2 * Math.PI / 3;
|
|
8669
|
+
var polar = narukawaFaceForward(relative[1] - base, relative[0]);
|
|
8670
|
+
var angle = polar[1] + facet.rotation + base / 2;
|
|
8671
|
+
var x = polar[0] * Math.cos(angle) + facet.x;
|
|
8672
|
+
var y = polar[0] * Math.sin(angle) + facet.y;
|
|
8673
|
+
return {
|
|
8674
|
+
x: x,
|
|
8675
|
+
y: y,
|
|
8676
|
+
facet: facet.id,
|
|
8677
|
+
sector: mod(sector, 3)
|
|
8678
|
+
};
|
|
8679
|
+
}
|
|
8680
|
+
|
|
8681
|
+
function applyConditionalLayout(raw, facet) {
|
|
8682
|
+
var x = raw.x;
|
|
8683
|
+
var y = raw.y;
|
|
8684
|
+
var oob = 0;
|
|
8685
|
+
var oobKey = 'normal';
|
|
8686
|
+
var folded = 0;
|
|
8687
|
+
var wrap = 0;
|
|
8688
|
+
|
|
8689
|
+
if (Math.abs(x) > 3 + EPS$1) {
|
|
8690
|
+
oobKey = x > 0 ? 'xpos' : 'xneg';
|
|
8691
|
+
x = 2 * facet.x - x;
|
|
8692
|
+
y = -y;
|
|
8693
|
+
oob = 1;
|
|
8694
|
+
} else if (Math.abs(y) > SQRT3$1 + EPS$1) {
|
|
8695
|
+
oobKey = y > 0 ? 'ypos' : 'yneg';
|
|
8696
|
+
x = -x;
|
|
8697
|
+
y = BLOCK_HEIGHT * Math.sign(y) - y;
|
|
8698
|
+
oob = 2;
|
|
8699
|
+
}
|
|
8700
|
+
|
|
8701
|
+
var qx = y;
|
|
8702
|
+
var qy = -x;
|
|
8703
|
+
if (qy > EPS$1) {
|
|
8704
|
+
qx = BLOCK_HEIGHT - qx;
|
|
8705
|
+
qy = -qy;
|
|
8706
|
+
folded = 1;
|
|
8707
|
+
}
|
|
8708
|
+
qx += LAYOUT_SHIFT;
|
|
8709
|
+
if (qx < 0) {
|
|
8710
|
+
qx += 2 * BLOCK_HEIGHT;
|
|
8711
|
+
wrap = 1;
|
|
8712
|
+
}
|
|
8713
|
+
x = qx - BLOCK_HEIGHT;
|
|
8714
|
+
y = qy + 1.5;
|
|
8715
|
+
x = clamp$2(x, XMIN, XMAX);
|
|
8716
|
+
y = clamp$2(y, YMIN, YMAX);
|
|
8717
|
+
return {
|
|
8718
|
+
x: x,
|
|
8719
|
+
y: y,
|
|
8720
|
+
facet: raw.facet,
|
|
8721
|
+
sector: raw.sector,
|
|
8722
|
+
oob: oob,
|
|
8723
|
+
oobKey: oobKey,
|
|
8724
|
+
folded: folded,
|
|
8725
|
+
wrap: wrap
|
|
8726
|
+
};
|
|
8727
|
+
}
|
|
8728
|
+
|
|
8729
|
+
function findForwardFacet(lam, phi, facets) {
|
|
8730
|
+
var best = null;
|
|
8731
|
+
var bestLat = -Infinity;
|
|
8732
|
+
for (var i = 0; i < 4; i++) {
|
|
8733
|
+
var facet = facets[i];
|
|
8734
|
+
var relative = obliquifySpherical(phi, lam, facet);
|
|
8735
|
+
if (relative[0] > bestLat) {
|
|
8736
|
+
bestLat = relative[0];
|
|
8737
|
+
best = facet;
|
|
8738
|
+
}
|
|
8739
|
+
}
|
|
8740
|
+
return best;
|
|
8741
|
+
}
|
|
8742
|
+
|
|
8743
|
+
function narukawaFaceForward(lam, phi) {
|
|
8744
|
+
var a = lam - Math.asin(Math.sin(lam) / SQRT3$1);
|
|
8745
|
+
var theta = Math.atan(2 * SQRT3$1 / Math.PI * a);
|
|
8746
|
+
var denominator = 2 + SQRT2$1 * Math.tan(phi);
|
|
8747
|
+
var q = denominator > 0 ? (2 + Math.cos(lam)) / denominator : 0;
|
|
8748
|
+
var r = q * SQRT3$1 / Math.cos(theta);
|
|
8749
|
+
return [r, theta];
|
|
8750
|
+
}
|
|
8751
|
+
|
|
8752
|
+
function narukawaFaceInverse(r, theta) {
|
|
8753
|
+
var target = Math.tan(theta) * Math.PI / (2 * SQRT3$1);
|
|
8754
|
+
var lo = -Math.PI / 3;
|
|
8755
|
+
var hi = Math.PI / 3;
|
|
8756
|
+
var lam;
|
|
8757
|
+
for (var i = 0; i < 55; i++) {
|
|
8758
|
+
lam = (lo + hi) / 2;
|
|
8759
|
+
var a = lam - Math.asin(Math.sin(lam) / SQRT3$1);
|
|
8760
|
+
if (a < target) lo = lam;
|
|
8761
|
+
else hi = lam;
|
|
8762
|
+
}
|
|
8763
|
+
lam = (lo + hi) / 2;
|
|
8764
|
+
var q = r * Math.cos(theta) / SQRT3$1;
|
|
8765
|
+
var phi = q < EPS$1 ? HALF_PI :
|
|
8766
|
+
Math.atan(((2 + Math.cos(lam)) / q - 2) / SQRT2$1);
|
|
8767
|
+
return [phi, lam];
|
|
8768
|
+
}
|
|
8769
|
+
|
|
8770
|
+
function invertLayout(x, y, facets) {
|
|
8771
|
+
var qx = x + BLOCK_HEIGHT;
|
|
8772
|
+
var qy = y - 1.5;
|
|
8773
|
+
var normalizedX = (qx - LAYOUT_SHIFT) / BLOCK_HEIGHT;
|
|
8774
|
+
if (normalizedX > 1.5) normalizedX -= 2;
|
|
8775
|
+
if (normalizedX > 0.5) {
|
|
8776
|
+
normalizedX = 1 - normalizedX;
|
|
8777
|
+
qy *= -1;
|
|
8778
|
+
}
|
|
8779
|
+
x = -qy;
|
|
8780
|
+
y = normalizedX * BLOCK_HEIGHT;
|
|
8781
|
+
|
|
8782
|
+
var facet = findInverseFacet(x, y, facets);
|
|
8783
|
+
var dx = x - facet.x;
|
|
8784
|
+
var dy = y - facet.y;
|
|
8785
|
+
var r = Math.hypot(dx, dy);
|
|
8786
|
+
var theta = normalizeRadians(Math.atan2(dy, dx) - facet.rotation);
|
|
8787
|
+
var base = Math.floor((theta + Math.PI / 6) / (Math.PI / 3)) *
|
|
8788
|
+
Math.PI / 3;
|
|
8789
|
+
var relative = narukawaFaceInverse(r, theta - base);
|
|
8790
|
+
relative[1] += base * 2;
|
|
8791
|
+
var p = deobliquifySpherical(relative[0], relative[1], facet);
|
|
8792
|
+
return [p[1], p[0]];
|
|
8793
|
+
}
|
|
8794
|
+
|
|
8795
|
+
function findInverseFacet(x, y, facets) {
|
|
8796
|
+
var best = null;
|
|
8797
|
+
var minDistance = Infinity;
|
|
8798
|
+
facets.forEach(function(facet) {
|
|
8799
|
+
var d = Math.hypot(x - facet.x, y - facet.y);
|
|
8800
|
+
if (d < minDistance) {
|
|
8801
|
+
minDistance = d;
|
|
8802
|
+
best = facet;
|
|
8803
|
+
}
|
|
8804
|
+
});
|
|
8805
|
+
return best;
|
|
8806
|
+
}
|
|
8807
|
+
|
|
8808
|
+
function createPublishedOrientation() {
|
|
8809
|
+
// Match the D3 Imago arrangement: the third published vertex is the
|
|
8810
|
+
// canonical southern vertex at longitude zero.
|
|
8811
|
+
var north = latLonToVector(GEOGRAPHIC_VERTICES[0]);
|
|
8812
|
+
var south = latLonToVector(GEOGRAPHIC_VERTICES[2]);
|
|
8813
|
+
var tangent = normalizeVector(subtract(
|
|
8814
|
+
south,
|
|
8815
|
+
multiply(north, dot$1(south, north))
|
|
8816
|
+
));
|
|
8817
|
+
var x = tangent;
|
|
8818
|
+
var y = cross$1(north, tangent);
|
|
8819
|
+
return {x: x, y: y, z: north};
|
|
8820
|
+
}
|
|
8821
|
+
|
|
8822
|
+
function toCanonical(lam, phi, orientation) {
|
|
8823
|
+
var v = radiansToVector(lam, phi);
|
|
8824
|
+
return [
|
|
8825
|
+
Math.atan2(dot$1(v, orientation.y), dot$1(v, orientation.x)),
|
|
8826
|
+
Math.asin(clamp$2(dot$1(v, orientation.z), -1, 1))
|
|
8827
|
+
];
|
|
8828
|
+
}
|
|
8829
|
+
|
|
8830
|
+
function fromCanonical(lam, phi, orientation) {
|
|
8831
|
+
var v = radiansToVector(lam, phi);
|
|
8832
|
+
var p = [
|
|
8833
|
+
orientation.x[0] * v[0] + orientation.y[0] * v[1] + orientation.z[0] * v[2],
|
|
8834
|
+
orientation.x[1] * v[0] + orientation.y[1] * v[1] + orientation.z[1] * v[2],
|
|
8835
|
+
orientation.x[2] * v[0] + orientation.y[2] * v[1] + orientation.z[2] * v[2]
|
|
8836
|
+
];
|
|
8837
|
+
return [Math.atan2(p[1], p[0]), Math.asin(clamp$2(p[2], -1, 1))];
|
|
8838
|
+
}
|
|
8839
|
+
|
|
8840
|
+
// Adapted from Justin Kunimune's Imago implementation.
|
|
8841
|
+
function obliquifySpherical(lat, lon, pole) {
|
|
8842
|
+
var lat0 = pole.lat;
|
|
8843
|
+
var lon0 = pole.lon;
|
|
8844
|
+
var theta0 = pole.meridian;
|
|
8845
|
+
var lat1;
|
|
8846
|
+
var lon1;
|
|
8847
|
+
if (Math.abs(lat0 - HALF_PI) < EPS$1) {
|
|
8848
|
+
lat1 = lat;
|
|
8849
|
+
lon1 = lon - lon0;
|
|
8850
|
+
} else {
|
|
8851
|
+
lat1 = Math.asin(clamp$2(
|
|
8852
|
+
Math.sin(lat0) * Math.sin(lat) +
|
|
8853
|
+
Math.cos(lat0) * Math.cos(lat) * Math.cos(lon0 - lon),
|
|
8854
|
+
-1,
|
|
8855
|
+
1
|
|
8856
|
+
));
|
|
8857
|
+
var denominator = Math.cos(lat1);
|
|
8858
|
+
var value = denominator < EPS$1 ? 1 :
|
|
8859
|
+
(Math.cos(lat0) * Math.sin(lat) -
|
|
8860
|
+
Math.sin(lat0) * Math.cos(lat) * Math.cos(lon0 - lon)) /
|
|
8861
|
+
denominator;
|
|
8862
|
+
lon1 = Math.acos(clamp$2(value, -1, 1)) - Math.PI;
|
|
8863
|
+
if (Math.sin(lon - lon0) > 0) lon1 = -lon1;
|
|
8864
|
+
}
|
|
8865
|
+
return [lat1, normalizeRadians(lon1 - theta0)];
|
|
8866
|
+
}
|
|
8867
|
+
|
|
8868
|
+
function deobliquifySpherical(lat, lon, pole) {
|
|
8869
|
+
var lat0 = pole.lat;
|
|
8870
|
+
var lon0 = pole.lon;
|
|
8871
|
+
lon += pole.meridian;
|
|
8872
|
+
var latOut = Math.asin(clamp$2(
|
|
8873
|
+
Math.sin(lat0) * Math.sin(lat) -
|
|
8874
|
+
Math.cos(lat0) * Math.cos(lon) * Math.cos(lat),
|
|
8875
|
+
-1,
|
|
8876
|
+
1
|
|
8877
|
+
));
|
|
8878
|
+
var lonOut;
|
|
8879
|
+
if (Math.abs(lat0 - HALF_PI) < EPS$1) {
|
|
8880
|
+
lonOut = lon + lon0;
|
|
8881
|
+
} else {
|
|
8882
|
+
var value = Math.sin(lat) / Math.cos(lat0) / Math.cos(latOut) -
|
|
8883
|
+
Math.tan(lat0) * Math.tan(latOut);
|
|
8884
|
+
if (Math.sin(lon) > 0) lonOut = lon0 + Math.acos(clamp$2(value, -1, 1));
|
|
8885
|
+
else lonOut = lon0 - Math.acos(clamp$2(value, -1, 1));
|
|
8886
|
+
}
|
|
8887
|
+
return [latOut, normalizeRadians(lonOut)];
|
|
8888
|
+
}
|
|
8889
|
+
|
|
8890
|
+
function createCutPaths(inverse, lon0) {
|
|
8891
|
+
// The rectangular edges become moderately curved geographic seams. Sampling
|
|
8892
|
+
// at about 0.03 degrees prevents straight mask chords from missing crossings.
|
|
8893
|
+
var n = 6000;
|
|
8894
|
+
var epsilon = 1e-8;
|
|
8895
|
+
var edges = [
|
|
8896
|
+
[[XMIN + epsilon, YMIN], [XMIN + epsilon, YMAX]],
|
|
8897
|
+
[[XMIN, YMAX - epsilon], [XMAX, YMAX - epsilon]],
|
|
8898
|
+
[[XMIN, YMIN + epsilon], [XMAX, YMIN + epsilon]]
|
|
8899
|
+
];
|
|
8900
|
+
var paths = edges.reduce(function(memo, edge) {
|
|
8901
|
+
var path = [];
|
|
8902
|
+
for (var i = 0; i <= n; i++) {
|
|
8903
|
+
var t = i / n;
|
|
8904
|
+
var x = edge[0][0] + (edge[1][0] - edge[0][0]) * t;
|
|
8905
|
+
var y = edge[0][1] + (edge[1][1] - edge[0][1]) * t;
|
|
8906
|
+
var p = inverse(x * EDGE_SCALE, y * EDGE_SCALE);
|
|
8907
|
+
path.push([
|
|
8908
|
+
normalizeLongitude$2(p[0] * R2D$2 + lon0),
|
|
8909
|
+
p[1] * R2D$2
|
|
8910
|
+
]);
|
|
8911
|
+
}
|
|
8912
|
+
return memo.concat(splitPathAtAntimeridian$1(path));
|
|
8913
|
+
}, []);
|
|
8914
|
+
return paths.map(function(part) {
|
|
8915
|
+
part.mask_width = 4e-5;
|
|
8916
|
+
return part;
|
|
8917
|
+
});
|
|
8918
|
+
}
|
|
8919
|
+
|
|
8920
|
+
function splitPathAtAntimeridian$1(path) {
|
|
8921
|
+
var paths = [];
|
|
8922
|
+
var part = [path[0]];
|
|
8923
|
+
for (var i = 1; i < path.length; i++) {
|
|
8924
|
+
var a = path[i - 1];
|
|
8925
|
+
var b = path[i];
|
|
8926
|
+
if (Math.abs(a[0] - b[0]) > 180) {
|
|
8927
|
+
var adjusted = b[0] + (b[0] < a[0] ? 360 : -360);
|
|
8928
|
+
var edge = a[0] < 0 ? -180 : 180;
|
|
8929
|
+
var t = (edge - a[0]) / (adjusted - a[0]);
|
|
8930
|
+
var lat = a[1] + (b[1] - a[1]) * t;
|
|
8931
|
+
part.push([edge, lat]);
|
|
8932
|
+
paths.push(part);
|
|
8933
|
+
part = [[-edge, lat], b];
|
|
8934
|
+
} else {
|
|
8935
|
+
part.push(b);
|
|
8936
|
+
}
|
|
8937
|
+
}
|
|
8938
|
+
if (part.length > 1) paths.push(part);
|
|
8939
|
+
return paths;
|
|
8940
|
+
}
|
|
8941
|
+
|
|
8942
|
+
function encodeRegion(state) {
|
|
8943
|
+
return ((((state.facet * 3 + state.sector) * 3 + state.oob) * 2 +
|
|
8944
|
+
state.folded) * 2 + state.wrap);
|
|
8945
|
+
}
|
|
8946
|
+
|
|
8947
|
+
function createRegionIndex() {
|
|
8948
|
+
var regions = [];
|
|
8949
|
+
for (var i = 0; i < 144; i++) {
|
|
8950
|
+
regions.push({id: i});
|
|
8951
|
+
}
|
|
8952
|
+
return regions;
|
|
8953
|
+
}
|
|
8954
|
+
|
|
8955
|
+
function latLonToVector(p) {
|
|
8956
|
+
return radiansToVector(p[1] * D2R$2, p[0] * D2R$2);
|
|
8957
|
+
}
|
|
8958
|
+
|
|
8959
|
+
function radiansToVector(lam, phi) {
|
|
8960
|
+
var cosPhi = Math.cos(phi);
|
|
8961
|
+
return [Math.cos(lam) * cosPhi, Math.sin(lam) * cosPhi, Math.sin(phi)];
|
|
8962
|
+
}
|
|
8963
|
+
|
|
8964
|
+
function subtract(a, b) {
|
|
8965
|
+
return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
|
|
8966
|
+
}
|
|
8967
|
+
|
|
8968
|
+
function multiply(a, k) {
|
|
8969
|
+
return [a[0] * k, a[1] * k, a[2] * k];
|
|
8970
|
+
}
|
|
8971
|
+
|
|
8972
|
+
function normalizeVector(a) {
|
|
8973
|
+
var k = 1 / Math.hypot(a[0], a[1], a[2]);
|
|
8974
|
+
return multiply(a, k);
|
|
8975
|
+
}
|
|
8976
|
+
|
|
8977
|
+
function cross$1(a, b) {
|
|
8978
|
+
return [
|
|
8979
|
+
a[1] * b[2] - a[2] * b[1],
|
|
8980
|
+
a[2] * b[0] - a[0] * b[2],
|
|
8981
|
+
a[0] * b[1] - a[1] * b[0]
|
|
8982
|
+
];
|
|
8983
|
+
}
|
|
8984
|
+
|
|
8985
|
+
function dot$1(a, b) {
|
|
8986
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
8987
|
+
}
|
|
8988
|
+
|
|
8989
|
+
function mod(a, n) {
|
|
8990
|
+
return (a % n + n) % n;
|
|
8991
|
+
}
|
|
8992
|
+
|
|
8993
|
+
function normalizeRadians(lam) {
|
|
8994
|
+
while (lam > Math.PI) lam -= 2 * Math.PI;
|
|
8995
|
+
while (lam < -Math.PI) lam += 2 * Math.PI;
|
|
8996
|
+
return lam;
|
|
8997
|
+
}
|
|
8998
|
+
|
|
8999
|
+
function normalizeLongitude$2(lon) {
|
|
9000
|
+
while (lon > 180) lon -= 360;
|
|
9001
|
+
while (lon < -180) lon += 360;
|
|
9002
|
+
return lon;
|
|
9003
|
+
}
|
|
9004
|
+
|
|
9005
|
+
function clamp$2(value, min, max) {
|
|
9006
|
+
return Math.max(min, Math.min(max, value));
|
|
9007
|
+
}
|
|
9008
|
+
|
|
9009
|
+
var Narukawa2022 = /*#__PURE__*/Object.freeze({
|
|
9010
|
+
__proto__: null,
|
|
9011
|
+
getNarukawa2022Engine: getNarukawa2022Engine,
|
|
9012
|
+
registerNarukawa2022Projection: registerNarukawa2022Projection
|
|
9013
|
+
});
|
|
9014
|
+
|
|
9015
|
+
/*
|
|
9016
|
+
* Rectangular conformal tetrahedral projections based on L. P. Lee's
|
|
9017
|
+
* conformal face transform.
|
|
9018
|
+
*
|
|
9019
|
+
* Lee transform and tetrahedral net adapted from d3-geo-polygon:
|
|
9020
|
+
* Copyright 2017-2024 Mike Bostock, ISC license.
|
|
9021
|
+
* https://github.com/d3/d3-geo-polygon/blob/main/src/tetrahedralLee.js
|
|
9022
|
+
*
|
|
9023
|
+
* The rectangular layout below is derived from Markley's repeated-face
|
|
9024
|
+
* construction: four affine copies of the triangular Lee net are clipped to
|
|
9025
|
+
* a 4/sqrt(3) frame. See F. Landis Markley, "Tetrahedral Map Projection"
|
|
9026
|
+
* (2020), and https://blog.map-projections.net/lee-markley-calm-and-grieger.
|
|
9027
|
+
*/
|
|
9028
|
+
|
|
9029
|
+
|
|
9030
|
+
var D2R$1 = Math.PI / 180;
|
|
9031
|
+
var R2D$1 = 180 / Math.PI;
|
|
9032
|
+
var SQRT2 = Math.sqrt(2);
|
|
9033
|
+
var SQRT3 = Math.sqrt(3);
|
|
9034
|
+
var ASIN_ONE_THIRD = Math.asin(1 / 3);
|
|
9035
|
+
var MARKLEY_LATITUDE = Math.acos(1 / 3) * 0.5 * R2D$1;
|
|
9036
|
+
var RECT_XMIN = -7;
|
|
9037
|
+
var RECT_XMAX = 1;
|
|
9038
|
+
var RECT_YMIN = -2 * SQRT3;
|
|
9039
|
+
var RECT_YMAX = 0;
|
|
9040
|
+
var EPS = 1e-12;
|
|
9041
|
+
var engines = {};
|
|
9042
|
+
|
|
9043
|
+
var TETRAHEDRON_VERTICES = [
|
|
9044
|
+
[0, 90],
|
|
9045
|
+
[-180, -ASIN_ONE_THIRD * R2D$1],
|
|
9046
|
+
[-60, -ASIN_ONE_THIRD * R2D$1],
|
|
9047
|
+
[60, -ASIN_ONE_THIRD * R2D$1]
|
|
9048
|
+
];
|
|
9049
|
+
|
|
9050
|
+
var TETRAHEDRON_FACES = [
|
|
9051
|
+
[1, 2, 3],
|
|
9052
|
+
[0, 2, 1],
|
|
9053
|
+
[0, 3, 2],
|
|
9054
|
+
[0, 1, 3]
|
|
9055
|
+
].map(function(face) {
|
|
9056
|
+
return face.map(function(i) {
|
|
9057
|
+
return TETRAHEDRON_VERTICES[i];
|
|
9058
|
+
});
|
|
9059
|
+
});
|
|
9060
|
+
|
|
9061
|
+
var LAYOUT_COPIES = [
|
|
9062
|
+
{id: 0, name: 'green', matrix: [1, 0, 0, 0, -1, 0]},
|
|
9063
|
+
{id: 1, name: 'red', matrix: [-1, 0, -4, 0, 1, 0]},
|
|
9064
|
+
{id: 2, name: 'blue', matrix: [1, 0, -8, 0, -1, 0]},
|
|
9065
|
+
{id: 3, name: 'orange', matrix: [-1, 0, 4, 0, 1, 0]}
|
|
9066
|
+
];
|
|
9067
|
+
|
|
9068
|
+
function registerLeeTetrahedralProjections(mproj) {
|
|
9069
|
+
if (!mproj) return;
|
|
9070
|
+
register('markley', 'Markley conformal tetrahedral world map');
|
|
9071
|
+
register('calm', 'Conformal Authagraph-Like Map');
|
|
9072
|
+
|
|
9073
|
+
function register(id, name) {
|
|
9074
|
+
if (mproj.internal.pj_list[id]) return;
|
|
9075
|
+
mproj.pj_add(function(P) {
|
|
9076
|
+
initLeeTetrahedral(P, id);
|
|
9077
|
+
}, id, name);
|
|
9078
|
+
}
|
|
9079
|
+
}
|
|
9080
|
+
|
|
9081
|
+
function getLeeTetrahedralEngine(id) {
|
|
9082
|
+
id = id || 'markley';
|
|
9083
|
+
if (!engines[id]) {
|
|
9084
|
+
engines[id] = createLeeTetrahedralEngine(getProjectionRotation(id));
|
|
9085
|
+
}
|
|
9086
|
+
return engines[id];
|
|
9087
|
+
}
|
|
9088
|
+
|
|
9089
|
+
function initLeeTetrahedral(P, id) {
|
|
9090
|
+
var engine = getLeeTetrahedralEngine(id);
|
|
9091
|
+
P.es = 0;
|
|
9092
|
+
P.inv = null;
|
|
9093
|
+
P.fwd = function(lp, xy) {
|
|
9094
|
+
var p = engine.forward(lp.lam, lp.phi);
|
|
9095
|
+
xy.x = p[0];
|
|
9096
|
+
xy.y = p[1];
|
|
9097
|
+
};
|
|
9098
|
+
P.__projection_topology = engine.getTopology(P.lam0 * R2D$1);
|
|
9099
|
+
P.__projected_outline = engine.outline;
|
|
9100
|
+
}
|
|
9101
|
+
|
|
9102
|
+
function getProjectionRotation(id) {
|
|
9103
|
+
if (id == 'calm') {
|
|
9104
|
+
// Exact D3 Euler equivalent of MapDesigner's published CALM aspect:
|
|
9105
|
+
// latitude 77°, longitude 143°, central meridian -163°.
|
|
9106
|
+
return [
|
|
9107
|
+
19.57956907750618,
|
|
9108
|
+
-12.42267097553935,
|
|
9109
|
+
3.8615690020132067
|
|
9110
|
+
];
|
|
9111
|
+
}
|
|
9112
|
+
// Markley's singularities are at ±35.26439°, in the oceans.
|
|
9113
|
+
return [115, MARKLEY_LATITUDE - 90, 180];
|
|
9114
|
+
}
|
|
9115
|
+
|
|
9116
|
+
function createLeeTetrahedralEngine(rotation) {
|
|
9117
|
+
var base = createPolyhedralProjection({
|
|
9118
|
+
faces: TETRAHEDRON_FACES,
|
|
9119
|
+
parents: [-1, 0, 0, 0],
|
|
9120
|
+
rotation: rotation,
|
|
9121
|
+
angle: 30,
|
|
9122
|
+
faceProjector: createLeeFaceProjector
|
|
9123
|
+
});
|
|
9124
|
+
var normalization = getBaseNormalization(base.outline);
|
|
9125
|
+
var baseTopology = base.getTopology(0);
|
|
9126
|
+
var sourceRegions = createSourceRegions(rotation);
|
|
9127
|
+
var pieces = createLayoutPieces(baseTopology.regions, normalization);
|
|
9128
|
+
var pieceIndex = new Map(pieces.map(function(piece) {
|
|
9129
|
+
return [getPieceKey(piece.face, piece.copy), piece.id];
|
|
9130
|
+
}));
|
|
9131
|
+
var outline = [[
|
|
9132
|
+
centerOutputPoint([RECT_XMIN, RECT_YMIN]),
|
|
9133
|
+
centerOutputPoint([RECT_XMAX, RECT_YMIN]),
|
|
9134
|
+
centerOutputPoint([RECT_XMAX, RECT_YMAX]),
|
|
9135
|
+
centerOutputPoint([RECT_XMIN, RECT_YMAX]),
|
|
9136
|
+
centerOutputPoint([RECT_XMIN, RECT_YMIN])
|
|
9137
|
+
]];
|
|
9138
|
+
|
|
9139
|
+
return {
|
|
9140
|
+
forward: forward,
|
|
9141
|
+
outline: outline,
|
|
9142
|
+
getTopology: getTopology
|
|
9143
|
+
};
|
|
9144
|
+
|
|
9145
|
+
function forward(lam, phi) {
|
|
9146
|
+
var p = normalizeBasePoint(base.forward(lam, phi), normalization);
|
|
9147
|
+
var copy = getLayoutCopy(p);
|
|
9148
|
+
return centerOutputPoint(applyMatrix(copy.matrix, p));
|
|
9149
|
+
}
|
|
9150
|
+
|
|
9151
|
+
function getTopology(lon0) {
|
|
9152
|
+
var topology = base.getTopology(lon0);
|
|
9153
|
+
return {
|
|
9154
|
+
regions: pieces.map(copyProjectedPiece),
|
|
9155
|
+
seams: topology.seams.map(function(seam) {
|
|
9156
|
+
return {
|
|
9157
|
+
type: 'cut',
|
|
9158
|
+
faces: seam.faces,
|
|
9159
|
+
paths: seam.paths
|
|
9160
|
+
};
|
|
9161
|
+
}),
|
|
9162
|
+
findRegion: findRegion,
|
|
9163
|
+
findTransitionRegion: findRegion,
|
|
9164
|
+
projectRegion: projectRegion,
|
|
9165
|
+
raster_regions: pieces.map(copyRasterPiece),
|
|
9166
|
+
raster_source_regions: sourceRegions.map(function(region) {
|
|
9167
|
+
return {
|
|
9168
|
+
id: region.id,
|
|
9169
|
+
boundary: region.boundary.map(function(p) {
|
|
9170
|
+
return [
|
|
9171
|
+
normalizeLongitude$1(p[0] + lon0),
|
|
9172
|
+
p[1]
|
|
9173
|
+
];
|
|
9174
|
+
})
|
|
9175
|
+
};
|
|
9176
|
+
}),
|
|
9177
|
+
raster_mesh_interval: 32,
|
|
9178
|
+
raster_cell_halo: false,
|
|
9179
|
+
fill_raster_mask: true,
|
|
9180
|
+
fill_raster_coverage: true,
|
|
9181
|
+
findRasterRegion: findRegion,
|
|
9182
|
+
projectRasterRegion: projectRegion,
|
|
9183
|
+
projectRasterSourceRegion: projectRasterSourceRegion,
|
|
9184
|
+
clipRasterRegionPolygon: clipRasterRegionPolygon,
|
|
9185
|
+
outline: outline.map(function(ring) {
|
|
9186
|
+
return ring.map(function(p) { return p.concat(); });
|
|
9187
|
+
})
|
|
9188
|
+
};
|
|
9189
|
+
|
|
9190
|
+
function findRegion(lon, lat) {
|
|
9191
|
+
var lam = normalizeLongitude$1(lon - lon0) * D2R$1;
|
|
9192
|
+
var phi = lat * D2R$1;
|
|
9193
|
+
var face = base.findFace(lam, phi);
|
|
9194
|
+
var p = normalizeBasePoint(base.forwardFace(lam, phi, face), normalization);
|
|
9195
|
+
var copy = getLayoutCopy(p);
|
|
9196
|
+
return pieceIndex.get(getPieceKey(face, copy.id));
|
|
9197
|
+
}
|
|
9198
|
+
|
|
9199
|
+
function projectRegion(lon, lat, regionId) {
|
|
9200
|
+
var piece = pieces[regionId];
|
|
9201
|
+
var lam = normalizeLongitude$1(lon - lon0) * D2R$1;
|
|
9202
|
+
var p = normalizeBasePoint(
|
|
9203
|
+
base.forwardFace(lam, lat * D2R$1, piece.face),
|
|
9204
|
+
normalization
|
|
9205
|
+
);
|
|
9206
|
+
return centerOutputPoint(applyMatrix(piece.matrix, p));
|
|
9207
|
+
}
|
|
9208
|
+
|
|
9209
|
+
function projectRasterSourceRegion(lon, lat, sourceRegionId) {
|
|
9210
|
+
var lam = normalizeLongitude$1(lon - lon0) * D2R$1;
|
|
9211
|
+
return normalizeBasePoint(
|
|
9212
|
+
base.forwardFace(lam, lat * D2R$1, sourceRegionId),
|
|
9213
|
+
normalization
|
|
9214
|
+
);
|
|
9215
|
+
}
|
|
9216
|
+
|
|
9217
|
+
function clipRasterRegionPolygon(vertices, regionId) {
|
|
9218
|
+
var piece = pieces[regionId];
|
|
9219
|
+
var polygon = vertices.map(function(vertex) {
|
|
9220
|
+
var p = applyMatrix(piece.matrix, [vertex.x, vertex.y]);
|
|
9221
|
+
return copyRasterVertex(vertex, p[0], p[1]);
|
|
9222
|
+
});
|
|
9223
|
+
polygon = clipRasterPolygonAxis(polygon, 'x', RECT_XMIN, true);
|
|
9224
|
+
polygon = clipRasterPolygonAxis(polygon, 'x', RECT_XMAX, false);
|
|
9225
|
+
polygon = clipRasterPolygonAxis(polygon, 'y', RECT_YMIN, true);
|
|
9226
|
+
polygon = clipRasterPolygonAxis(polygon, 'y', RECT_YMAX, false);
|
|
9227
|
+
polygon.forEach(function(vertex) {
|
|
9228
|
+
var p = centerOutputPoint([vertex.x, vertex.y]);
|
|
9229
|
+
vertex.x = p[0];
|
|
9230
|
+
vertex.y = p[1];
|
|
9231
|
+
});
|
|
9232
|
+
return polygon;
|
|
9233
|
+
}
|
|
9234
|
+
}
|
|
9235
|
+
}
|
|
9236
|
+
|
|
9237
|
+
function createSourceRegions(rotation) {
|
|
9238
|
+
return TETRAHEDRON_FACES.map(function(face, id) {
|
|
9239
|
+
var boundary = face.map(function(p) {
|
|
9240
|
+
var q = rotateSphericalRadians(
|
|
9241
|
+
p[0] * D2R$1, p[1] * D2R$1, rotation, true);
|
|
9242
|
+
return [normalizeLongitude$1(q[0] * R2D$1), q[1] * R2D$1];
|
|
9243
|
+
});
|
|
9244
|
+
boundary.push(boundary[0].concat());
|
|
9245
|
+
return {id: id, boundary: boundary};
|
|
9246
|
+
});
|
|
9247
|
+
}
|
|
9248
|
+
|
|
9249
|
+
function createLayoutPieces(regions, normalization) {
|
|
9250
|
+
var pieces = [];
|
|
9251
|
+
regions.forEach(function(region) {
|
|
9252
|
+
var boundary = region.projected_boundary.map(function(p) {
|
|
9253
|
+
return normalizeBasePoint(p, normalization);
|
|
9254
|
+
});
|
|
9255
|
+
LAYOUT_COPIES.forEach(function(copy) {
|
|
9256
|
+
var polygon = boundary.map(function(p) {
|
|
9257
|
+
return applyMatrix(copy.matrix, p);
|
|
9258
|
+
});
|
|
9259
|
+
polygon = clipPolygonAxis(polygon, 0, RECT_XMIN, true);
|
|
9260
|
+
polygon = clipPolygonAxis(polygon, 0, RECT_XMAX, false);
|
|
9261
|
+
polygon = clipPolygonAxis(polygon, 1, RECT_YMIN, true);
|
|
9262
|
+
polygon = clipPolygonAxis(polygon, 1, RECT_YMAX, false);
|
|
9263
|
+
if (polygon.length < 3 || Math.abs(getRingArea$2(polygon)) < EPS) return;
|
|
9264
|
+
var id = pieces.length;
|
|
9265
|
+
pieces.push({
|
|
9266
|
+
id: id,
|
|
9267
|
+
face: region.id,
|
|
9268
|
+
source_region: region.id,
|
|
9269
|
+
copy: copy.id,
|
|
9270
|
+
matrix: copy.matrix,
|
|
9271
|
+
boundary: polygon.map(centerOutputPoint)
|
|
9272
|
+
});
|
|
9273
|
+
});
|
|
9274
|
+
});
|
|
9275
|
+
return pieces;
|
|
9276
|
+
}
|
|
9277
|
+
|
|
9278
|
+
function copyProjectedPiece(piece) {
|
|
9279
|
+
return {
|
|
9280
|
+
id: piece.id,
|
|
9281
|
+
source_region: piece.source_region,
|
|
9282
|
+
projected_boundary: closeRing$1(piece.boundary)
|
|
9283
|
+
};
|
|
9284
|
+
}
|
|
9285
|
+
|
|
9286
|
+
function copyRasterPiece(piece) {
|
|
9287
|
+
return {
|
|
9288
|
+
id: piece.id,
|
|
9289
|
+
source_region: piece.source_region,
|
|
9290
|
+
projected_boundary: closeRing$1(piece.boundary)
|
|
9291
|
+
};
|
|
9292
|
+
}
|
|
9293
|
+
|
|
9294
|
+
function closeRing$1(ring) {
|
|
9295
|
+
var copy = ring.map(function(p) { return p.concat(); });
|
|
9296
|
+
if (copy.length && !pointsEqual$1(copy[0], copy[copy.length - 1])) {
|
|
9297
|
+
copy.push(copy[0].concat());
|
|
9298
|
+
}
|
|
9299
|
+
return copy;
|
|
9300
|
+
}
|
|
9301
|
+
|
|
9302
|
+
function getLayoutCopy(p) {
|
|
9303
|
+
// The four transformed triangular nets tile the frame. These two straight
|
|
9304
|
+
// cuts select the unique copy containing a point from the base net.
|
|
9305
|
+
if (p[1] >= 0) return p[0] > 3 ? LAYOUT_COPIES[2] : LAYOUT_COPIES[0];
|
|
9306
|
+
return p[0] > 1 ? LAYOUT_COPIES[3] : LAYOUT_COPIES[1];
|
|
9307
|
+
}
|
|
9308
|
+
|
|
9309
|
+
function centerOutputPoint(p) {
|
|
9310
|
+
return [
|
|
9311
|
+
p[0] - (RECT_XMIN + RECT_XMAX) / 2,
|
|
9312
|
+
p[1] - (RECT_YMIN + RECT_YMAX) / 2
|
|
9313
|
+
];
|
|
9314
|
+
}
|
|
9315
|
+
|
|
9316
|
+
function getBaseNormalization(outline) {
|
|
9317
|
+
var xmin = Infinity;
|
|
9318
|
+
var ymin = Infinity;
|
|
9319
|
+
var xmax = -Infinity;
|
|
9320
|
+
var ymax = -Infinity;
|
|
9321
|
+
outline.forEach(function(ring) {
|
|
9322
|
+
ring.forEach(function(p) {
|
|
9323
|
+
xmin = Math.min(xmin, p[0]);
|
|
9324
|
+
ymin = Math.min(ymin, p[1]);
|
|
9325
|
+
xmax = Math.max(xmax, p[0]);
|
|
9326
|
+
ymax = Math.max(ymax, p[1]);
|
|
9327
|
+
});
|
|
9328
|
+
});
|
|
9329
|
+
return {
|
|
9330
|
+
cx: (xmin + xmax) / 2,
|
|
9331
|
+
cy: (ymin + ymax) / 2,
|
|
9332
|
+
scale: 8 / (xmax - xmin)
|
|
9333
|
+
};
|
|
9334
|
+
}
|
|
9335
|
+
|
|
9336
|
+
function normalizeBasePoint(p, normalization) {
|
|
9337
|
+
return [
|
|
9338
|
+
(p[0] - normalization.cx) * normalization.scale,
|
|
9339
|
+
-(p[1] - normalization.cy) * normalization.scale
|
|
9340
|
+
];
|
|
9341
|
+
}
|
|
9342
|
+
|
|
9343
|
+
function createLeeFaceProjector(face) {
|
|
9344
|
+
var c = face.centroid;
|
|
9345
|
+
var rotation = Math.abs(c[1]) == 90 ?
|
|
9346
|
+
[0, -c[1], -30] :
|
|
9347
|
+
[-c[0], -c[1], 30];
|
|
9348
|
+
return function(lam, phi) {
|
|
9349
|
+
var p = rotateSphericalRadians(lam, phi, rotation);
|
|
9350
|
+
var q = leeRaw(p[0], p[1]);
|
|
9351
|
+
return [q[0], -q[1]];
|
|
9352
|
+
};
|
|
9353
|
+
}
|
|
9354
|
+
|
|
9355
|
+
function leeRaw(lam, phi) {
|
|
9356
|
+
var w = [-0.5, SQRT3 / 2];
|
|
9357
|
+
var z = complexMultiply(stereographicRaw(lam, phi), [SQRT2, 0]);
|
|
9358
|
+
var powers = [0, 1, 2].map(function(i) {
|
|
9359
|
+
return complexPower(w, [i, 0]);
|
|
9360
|
+
});
|
|
9361
|
+
var sector = 0;
|
|
9362
|
+
for (var i = 1; i < powers.length; i++) {
|
|
9363
|
+
if (complexMultiply(z, powers[i])[0] >
|
|
9364
|
+
complexMultiply(z, powers[sector])[0]) sector = i;
|
|
9365
|
+
}
|
|
9366
|
+
var rot = powers[sector];
|
|
9367
|
+
var n = complexNorm(z);
|
|
9368
|
+
var h = [0, 0];
|
|
9369
|
+
var k = [0, 0];
|
|
9370
|
+
|
|
9371
|
+
if (n > 0.3) {
|
|
9372
|
+
var y = complexSubtract([1, 0], complexMultiply(rot, z));
|
|
9373
|
+
var w1 = 1.4021821053254548;
|
|
9374
|
+
var coefficients = [
|
|
9375
|
+
1.15470053837925, 0.192450089729875, 0.0481125224324687,
|
|
9376
|
+
0.010309826235529, 3.34114739114366e-4, -0.00150351632601465,
|
|
9377
|
+
-0.0012304417796231, -675190201960282e-18,
|
|
9378
|
+
-284084537293856e-18, -821205120500051e-19,
|
|
9379
|
+
-159257630018706e-20, 1.91691805888369e-5,
|
|
9380
|
+
1.73095888028726e-5, 1.03865580818367e-5,
|
|
9381
|
+
4.70614523937179e-6, 1.4413500104181e-6,
|
|
9382
|
+
1.92757960170179e-8, -3.82869799649063e-7,
|
|
9383
|
+
-3.57526015225576e-7, -2.2175964844211e-7
|
|
9384
|
+
];
|
|
9385
|
+
var g = [0, 0];
|
|
9386
|
+
for (i = coefficients.length - 1; i >= 0; i--) {
|
|
9387
|
+
g = complexAdd([coefficients[i], 0], complexMultiply(g, y));
|
|
9388
|
+
}
|
|
9389
|
+
k = complexSubtract([w1, 0], complexMultiply(complexPower(y, 0.5), g));
|
|
9390
|
+
k = complexMultiply(complexMultiply(k, rot), rot);
|
|
9391
|
+
}
|
|
9392
|
+
|
|
9393
|
+
if (n < 0.5) {
|
|
9394
|
+
var h0 = [1, 1 / 8, 3 / 56, 1 / 32, 35 / 1664, 63 / 4096, 231 / 19456];
|
|
9395
|
+
var z3 = complexPower(z, [3, 0]);
|
|
9396
|
+
for (i = h0.length - 1; i >= 0; i--) {
|
|
9397
|
+
h = complexAdd([h0[i], 0], complexMultiply(h, z3));
|
|
9398
|
+
}
|
|
9399
|
+
h = complexMultiply(h, z);
|
|
9400
|
+
}
|
|
9401
|
+
|
|
9402
|
+
if (n < 0.3) return h;
|
|
9403
|
+
if (n > 0.5) return k;
|
|
9404
|
+
var t = (n - 0.3) / 0.2;
|
|
9405
|
+
return complexAdd(
|
|
9406
|
+
complexMultiply(k, [t, 0]),
|
|
9407
|
+
complexMultiply(h, [1 - t, 0])
|
|
9408
|
+
);
|
|
9409
|
+
}
|
|
9410
|
+
|
|
9411
|
+
function stereographicRaw(lam, phi) {
|
|
9412
|
+
var cosPhi = Math.cos(phi);
|
|
9413
|
+
var k = 1 / (1 + cosPhi * Math.cos(lam));
|
|
9414
|
+
return [k * cosPhi * Math.sin(lam), k * Math.sin(phi)];
|
|
9415
|
+
}
|
|
9416
|
+
|
|
9417
|
+
function complexAdd(a, b) {
|
|
9418
|
+
return [a[0] + b[0], a[1] + b[1]];
|
|
9419
|
+
}
|
|
9420
|
+
|
|
9421
|
+
function complexSubtract(a, b) {
|
|
9422
|
+
return [a[0] - b[0], a[1] - b[1]];
|
|
9423
|
+
}
|
|
9424
|
+
|
|
9425
|
+
function complexMultiply(a, b) {
|
|
9426
|
+
return [a[0] * b[0] - a[1] * b[1], a[1] * b[0] + a[0] * b[1]];
|
|
9427
|
+
}
|
|
9428
|
+
|
|
9429
|
+
function complexNorm(a) {
|
|
9430
|
+
return Math.hypot(a[0], a[1]);
|
|
9431
|
+
}
|
|
9432
|
+
|
|
9433
|
+
function complexPower(value, exponent) {
|
|
9434
|
+
var a = value[0];
|
|
9435
|
+
var b = value[1];
|
|
9436
|
+
var n = typeof exponent == 'number' ? [exponent, 0] : exponent;
|
|
9437
|
+
if (a === 0 && b === 0) return [0, 0];
|
|
9438
|
+
if (!n[1] && b === 0 && a >= 0) {
|
|
9439
|
+
return [Math.pow(a, n[0]), 0];
|
|
9440
|
+
}
|
|
9441
|
+
var arg = Math.atan2(b, a);
|
|
9442
|
+
var logNorm = Math.log(Math.hypot(a, b));
|
|
9443
|
+
var magnitude = Math.exp(n[0] * logNorm - n[1] * arg);
|
|
9444
|
+
var angle = n[1] * logNorm + n[0] * arg;
|
|
9445
|
+
return [magnitude * Math.cos(angle), magnitude * Math.sin(angle)];
|
|
9446
|
+
}
|
|
9447
|
+
|
|
9448
|
+
function applyMatrix(m, p) {
|
|
9449
|
+
return [
|
|
9450
|
+
m[0] * p[0] + m[1] * p[1] + m[2],
|
|
9451
|
+
m[3] * p[0] + m[4] * p[1] + m[5]
|
|
9452
|
+
];
|
|
9453
|
+
}
|
|
9454
|
+
|
|
9455
|
+
function clipPolygonAxis(polygon, axis, value, keepGreater) {
|
|
9456
|
+
var output = [];
|
|
9457
|
+
if (!polygon.length) return output;
|
|
9458
|
+
var a = polygon[polygon.length - 1];
|
|
9459
|
+
var aInside = keepGreater ? a[axis] >= value - EPS : a[axis] <= value + EPS;
|
|
9460
|
+
polygon.forEach(function(b) {
|
|
9461
|
+
var bInside = keepGreater ? b[axis] >= value - EPS : b[axis] <= value + EPS;
|
|
9462
|
+
if (aInside != bInside) {
|
|
9463
|
+
var t = (value - a[axis]) / (b[axis] - a[axis]);
|
|
9464
|
+
var p = [
|
|
9465
|
+
a[0] + (b[0] - a[0]) * t,
|
|
9466
|
+
a[1] + (b[1] - a[1]) * t
|
|
9467
|
+
];
|
|
9468
|
+
p[axis] = value;
|
|
9469
|
+
output.push(p);
|
|
9470
|
+
}
|
|
9471
|
+
if (bInside) output.push(b.concat());
|
|
9472
|
+
a = b;
|
|
9473
|
+
aInside = bInside;
|
|
9474
|
+
});
|
|
9475
|
+
return output;
|
|
9476
|
+
}
|
|
9477
|
+
|
|
9478
|
+
function clipRasterPolygonAxis(polygon, axis, value, keepGreater) {
|
|
9479
|
+
var output = [];
|
|
9480
|
+
if (!polygon.length) return output;
|
|
9481
|
+
var a = polygon[polygon.length - 1];
|
|
9482
|
+
var aInside = keepGreater ? a[axis] >= value - EPS : a[axis] <= value + EPS;
|
|
9483
|
+
polygon.forEach(function(b) {
|
|
9484
|
+
var bInside = keepGreater ? b[axis] >= value - EPS : b[axis] <= value + EPS;
|
|
9485
|
+
if (aInside != bInside) {
|
|
9486
|
+
var t = (value - a[axis]) / (b[axis] - a[axis]);
|
|
9487
|
+
var vertex = {
|
|
9488
|
+
x: a.x + (b.x - a.x) * t,
|
|
9489
|
+
y: a.y + (b.y - a.y) * t,
|
|
9490
|
+
sx: a.sx + (b.sx - a.sx) * t,
|
|
9491
|
+
sy: a.sy + (b.sy - a.sy) * t,
|
|
9492
|
+
lon: interpolateLongitude(a.lon, b.lon, t),
|
|
9493
|
+
lat: a.lat + (b.lat - a.lat) * t
|
|
9494
|
+
};
|
|
9495
|
+
vertex[axis] = value;
|
|
9496
|
+
output.push(vertex);
|
|
9497
|
+
}
|
|
9498
|
+
if (bInside) output.push(copyRasterVertex(b, b.x, b.y));
|
|
9499
|
+
a = b;
|
|
9500
|
+
aInside = bInside;
|
|
9501
|
+
});
|
|
9502
|
+
return output;
|
|
9503
|
+
}
|
|
9504
|
+
|
|
9505
|
+
function copyRasterVertex(vertex, x, y) {
|
|
9506
|
+
return {
|
|
9507
|
+
x: x,
|
|
9508
|
+
y: y,
|
|
9509
|
+
sx: vertex.sx,
|
|
9510
|
+
sy: vertex.sy,
|
|
9511
|
+
lon: vertex.lon,
|
|
9512
|
+
lat: vertex.lat
|
|
9513
|
+
};
|
|
9514
|
+
}
|
|
9515
|
+
|
|
9516
|
+
function interpolateLongitude(a, b, t) {
|
|
9517
|
+
var delta = b - a;
|
|
9518
|
+
if (delta > 180) delta -= 360;
|
|
9519
|
+
if (delta < -180) delta += 360;
|
|
9520
|
+
return normalizeLongitude$1(a + delta * t);
|
|
9521
|
+
}
|
|
9522
|
+
|
|
9523
|
+
function getRingArea$2(ring) {
|
|
9524
|
+
var area = 0;
|
|
9525
|
+
for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
9526
|
+
area += ring[j][0] * ring[i][1] - ring[i][0] * ring[j][1];
|
|
9527
|
+
}
|
|
9528
|
+
return area / 2;
|
|
9529
|
+
}
|
|
9530
|
+
|
|
9531
|
+
function getPieceKey(face, copy) {
|
|
9532
|
+
return face + ':' + copy;
|
|
9533
|
+
}
|
|
9534
|
+
|
|
9535
|
+
function pointsEqual$1(a, b) {
|
|
9536
|
+
return Math.abs(a[0] - b[0]) < EPS && Math.abs(a[1] - b[1]) < EPS;
|
|
9537
|
+
}
|
|
9538
|
+
|
|
9539
|
+
function normalizeLongitude$1(lon) {
|
|
9540
|
+
lon = (lon + 180) % 360;
|
|
9541
|
+
if (lon < 0) lon += 360;
|
|
9542
|
+
return lon - 180;
|
|
9543
|
+
}
|
|
9544
|
+
|
|
8088
9545
|
var mproj$1 = require$1('mproj');
|
|
8089
9546
|
registerDymaxionProjections(mproj$1);
|
|
8090
9547
|
registerButterflyProjections(mproj$1);
|
|
9548
|
+
registerNarukawa2022Projection(mproj$1);
|
|
9549
|
+
registerLeeTetrahedralProjections(mproj$1);
|
|
8091
9550
|
|
|
8092
9551
|
var asyncLoader = null;
|
|
8093
9552
|
|
|
@@ -11075,7 +12534,7 @@
|
|
|
11075
12534
|
function layerNameIsUnsafeFilename(name) {
|
|
11076
12535
|
name = String(name);
|
|
11077
12536
|
// path separators (directory traversal on any OS) or NUL
|
|
11078
|
-
if (/[
|
|
12537
|
+
if (/[/\\\0]/.test(name)) return true;
|
|
11079
12538
|
// Windows drive-relative prefix, e.g. "C:foo" can write to another drive
|
|
11080
12539
|
if (/^[A-Za-z]:/.test(name)) return true;
|
|
11081
12540
|
return false;
|
|
@@ -40970,7 +42429,9 @@ ${svg}
|
|
|
40970
42429
|
return finalizeImportedDataset(dataset, dataFmt, data, opts);
|
|
40971
42430
|
}
|
|
40972
42431
|
|
|
40973
|
-
|
|
42432
|
+
// Canonical content import interface. Always resolves to an array because some
|
|
42433
|
+
// formats (notably GeoPackage) may contain datasets that cannot be merged.
|
|
42434
|
+
async function importDatasetsFromContent(obj, opts) {
|
|
40974
42435
|
var dataset, dataFmt, data;
|
|
40975
42436
|
opts = opts || {};
|
|
40976
42437
|
if (obj.fgb) {
|
|
@@ -40994,14 +42455,16 @@ ${svg}
|
|
|
40994
42455
|
data = obj[dataFmt];
|
|
40995
42456
|
dataset = await importImageRaster(obj, opts);
|
|
40996
42457
|
} else {
|
|
40997
|
-
return importContent(obj, opts);
|
|
42458
|
+
return normalizeImportedDatasets$1(importContent(obj, opts));
|
|
40998
42459
|
}
|
|
40999
|
-
|
|
41000
|
-
return
|
|
41001
|
-
|
|
41002
|
-
|
|
41003
|
-
|
|
41004
|
-
|
|
42460
|
+
return normalizeImportedDatasets$1(dataset).map(function(ds) {
|
|
42461
|
+
return finalizeImportedDataset(ds, dataFmt, data, opts);
|
|
42462
|
+
});
|
|
42463
|
+
}
|
|
42464
|
+
|
|
42465
|
+
// Compatibility facade for callers that expect one dataset when possible.
|
|
42466
|
+
async function importContentAsync(obj, opts) {
|
|
42467
|
+
return denormalizeImportedDatasets$1(await importDatasetsFromContent(obj, opts));
|
|
41005
42468
|
}
|
|
41006
42469
|
|
|
41007
42470
|
// Deprecated (included for compatibility with older tests)
|
|
@@ -41012,6 +42475,14 @@ ${svg}
|
|
|
41012
42475
|
return importContent(input, opts);
|
|
41013
42476
|
}
|
|
41014
42477
|
|
|
42478
|
+
function normalizeImportedDatasets$1(datasetOrArray) {
|
|
42479
|
+
return Array.isArray(datasetOrArray) ? datasetOrArray : [datasetOrArray];
|
|
42480
|
+
}
|
|
42481
|
+
|
|
42482
|
+
function denormalizeImportedDatasets$1(datasets) {
|
|
42483
|
+
return datasets.length == 1 ? datasets[0] : datasets;
|
|
42484
|
+
}
|
|
42485
|
+
|
|
41015
42486
|
|
|
41016
42487
|
function importShapefile(obj, opts) {
|
|
41017
42488
|
var shpSrc = obj.shp.content || obj.shp.filename, // read from a file if (binary) content is missing
|
|
@@ -41094,6 +42565,7 @@ ${svg}
|
|
|
41094
42565
|
__proto__: null,
|
|
41095
42566
|
importContent: importContent,
|
|
41096
42567
|
importContentAsync: importContentAsync,
|
|
42568
|
+
importDatasetsFromContent: importDatasetsFromContent,
|
|
41097
42569
|
importFileContent: importFileContent
|
|
41098
42570
|
});
|
|
41099
42571
|
|
|
@@ -41262,8 +42734,7 @@ ${svg}
|
|
|
41262
42734
|
var dataset, datasets, target;
|
|
41263
42735
|
|
|
41264
42736
|
if (opts.stdin) {
|
|
41265
|
-
|
|
41266
|
-
datasets = normalizeImportedDatasets(dataset);
|
|
42737
|
+
datasets = await importDatasetsFromFile('/dev/stdin', opts);
|
|
41267
42738
|
catalog.addDatasets(datasets);
|
|
41268
42739
|
if (datasets.length > 1) {
|
|
41269
42740
|
catalog.setDefaultTargets(datasets.map(function(ds) {
|
|
@@ -41301,11 +42772,11 @@ ${svg}
|
|
|
41301
42772
|
}
|
|
41302
42773
|
|
|
41303
42774
|
if (files.length == 1) {
|
|
41304
|
-
|
|
42775
|
+
datasets = await importDatasetsFromFile(files[0], opts);
|
|
41305
42776
|
} else {
|
|
41306
42777
|
dataset = await importFilesTogetherAsync(files, opts);
|
|
42778
|
+
datasets = [dataset];
|
|
41307
42779
|
}
|
|
41308
|
-
datasets = normalizeImportedDatasets(dataset);
|
|
41309
42780
|
datasets = validateAndCleanGpkgSelection(datasets, opts);
|
|
41310
42781
|
|
|
41311
42782
|
if (opts.merge_files && files.length > 1) {
|
|
@@ -41422,9 +42893,12 @@ ${svg}
|
|
|
41422
42893
|
});
|
|
41423
42894
|
}
|
|
41424
42895
|
|
|
41425
|
-
// Let the web UI replace
|
|
42896
|
+
// Let the web UI replace path-based imports with a browser-friendly resolver.
|
|
41426
42897
|
function replaceImportFile(func) {
|
|
41427
42898
|
_importFile = func;
|
|
42899
|
+
_importDatasetsFromFile = async function(path, opts) {
|
|
42900
|
+
return normalizeImportedDatasets(await func(path, opts));
|
|
42901
|
+
};
|
|
41428
42902
|
}
|
|
41429
42903
|
|
|
41430
42904
|
function importFile(path, opts) {
|
|
@@ -41432,69 +42906,29 @@ ${svg}
|
|
|
41432
42906
|
}
|
|
41433
42907
|
|
|
41434
42908
|
async function importFileAsync(path, opts) {
|
|
41435
|
-
return
|
|
42909
|
+
return denormalizeImportedDatasets(await importDatasetsFromFile(path, opts));
|
|
41436
42910
|
}
|
|
41437
42911
|
|
|
41438
|
-
|
|
41439
|
-
|
|
41440
|
-
|
|
41441
|
-
|
|
41442
|
-
cache = opts && opts.input || null,
|
|
41443
|
-
cached = cache && (path in cache),
|
|
41444
|
-
content;
|
|
41445
|
-
|
|
41446
|
-
cli.checkFileExists(path, cache);
|
|
41447
|
-
|
|
41448
|
-
if ((fileType == 'shp' || fileType == 'json' || fileType == 'text' || fileType == 'dbf' ||
|
|
41449
|
-
fileType == 'gpkg') && !cached) {
|
|
41450
|
-
// these file types are read incrementally
|
|
41451
|
-
content = null;
|
|
41452
|
-
|
|
41453
|
-
} else if (fileType && isSupportedBinaryInputType(path)) {
|
|
41454
|
-
content = cli.readFile(path, null, cache);
|
|
41455
|
-
if (utils.isString(content)) {
|
|
41456
|
-
// Fix for issue #264 (applyCommands() input is file path instead of binary content)
|
|
41457
|
-
stop$1('Expected binary content, received a string');
|
|
41458
|
-
}
|
|
41459
|
-
|
|
41460
|
-
} else if (fileType) { // string type, e.g. kml, geojson
|
|
41461
|
-
content = cli.readFile(path, encoding || 'utf-8', cache);
|
|
41462
|
-
|
|
41463
|
-
} else if (getFileExtension(path) == 'gz') {
|
|
41464
|
-
var pathgz = path;
|
|
41465
|
-
path = pathgz.replace(/\.gz$/, '');
|
|
41466
|
-
fileType = guessInputFileType(path);
|
|
41467
|
-
if (!fileType) {
|
|
41468
|
-
stop$1('Unrecognized file type:', path);
|
|
41469
|
-
}
|
|
41470
|
-
content = gunzipSync(cli.readFile(pathgz, null, cache), path);
|
|
41471
|
-
|
|
41472
|
-
} else { // type can't be inferred from filename -- try reading as text
|
|
41473
|
-
content = cli.readFile(path, encoding || 'utf-8', cache);
|
|
41474
|
-
fileType = guessInputContentType(content);
|
|
41475
|
-
if (fileType == 'text' && content.indexOf('\ufffd') > -1) {
|
|
41476
|
-
// invalidate string data that contains the 'replacement character'
|
|
41477
|
-
fileType = null;
|
|
41478
|
-
}
|
|
41479
|
-
}
|
|
42912
|
+
// Canonical path import interface.
|
|
42913
|
+
async function importDatasetsFromFile(path, opts) {
|
|
42914
|
+
return _importDatasetsFromFile(path, opts);
|
|
42915
|
+
}
|
|
41480
42916
|
|
|
41481
|
-
|
|
41482
|
-
|
|
41483
|
-
}
|
|
41484
|
-
input[fileType] = {filename: path, content: content};
|
|
41485
|
-
content = null; // for g.c.
|
|
41486
|
-
if (fileType == 'shp' || fileType == 'dbf') {
|
|
41487
|
-
readShapefileAuxFiles(path, input, cache);
|
|
41488
|
-
} else if (isRasterImageInputType(fileType)) {
|
|
41489
|
-
readRasterImageAuxFiles(path, input, cache);
|
|
41490
|
-
}
|
|
41491
|
-
if (fileType == 'shp' && !input.dbf) {
|
|
41492
|
-
message(utils.format("[%s] .dbf file is missing - shapes imported without attribute data.", path));
|
|
41493
|
-
}
|
|
42917
|
+
var _importFile = function(path, opts) {
|
|
42918
|
+
var input = prepareImportFile(path, opts);
|
|
41494
42919
|
return importContent(input, opts);
|
|
41495
42920
|
};
|
|
41496
42921
|
|
|
41497
|
-
async function
|
|
42922
|
+
var _importDatasetsFromFile = async function(path, opts) {
|
|
42923
|
+
var input = prepareImportFile(path, opts);
|
|
42924
|
+
return importDatasetsFromContent(input, opts);
|
|
42925
|
+
};
|
|
42926
|
+
|
|
42927
|
+
// Read a file (or cache entry) and collect any sidecars into the normalized
|
|
42928
|
+
// content-group shape consumed by the content importers.
|
|
42929
|
+
// File acquisition is currently synchronous in both import paths; only some
|
|
42930
|
+
// format parsers require asynchronous work.
|
|
42931
|
+
function prepareImportFile(path, opts) {
|
|
41498
42932
|
var fileType = guessInputFileType(path),
|
|
41499
42933
|
input = {},
|
|
41500
42934
|
encoding = opts && opts.encoding || null,
|
|
@@ -41504,7 +42938,8 @@ ${svg}
|
|
|
41504
42938
|
|
|
41505
42939
|
cli.checkFileExists(path, cache);
|
|
41506
42940
|
|
|
41507
|
-
if ((fileType == 'shp' || fileType == 'json' || fileType == 'text' || fileType == 'dbf'
|
|
42941
|
+
if ((fileType == 'shp' || fileType == 'json' || fileType == 'text' || fileType == 'dbf' ||
|
|
42942
|
+
fileType == 'gpkg') && !cached) {
|
|
41508
42943
|
// these file types are read incrementally
|
|
41509
42944
|
content = null;
|
|
41510
42945
|
|
|
@@ -41547,37 +42982,10 @@ ${svg}
|
|
|
41547
42982
|
if (fileType == 'shp' && !input.dbf) {
|
|
41548
42983
|
message(utils.format("[%s] .dbf file is missing - shapes imported without attribute data.", path));
|
|
41549
42984
|
}
|
|
41550
|
-
return
|
|
41551
|
-
}
|
|
41552
|
-
|
|
41553
|
-
// Import multiple files to a single dataset
|
|
41554
|
-
function importFilesTogether(files, opts) {
|
|
41555
|
-
var unbuiltTopology = false;
|
|
41556
|
-
var datasets = files.reduce(function(memo, fname) {
|
|
41557
|
-
// import without topology or snapping
|
|
41558
|
-
var importOpts = utils.defaults({no_topology: true, snap: false, snap_interval: null, files: [fname]}, opts);
|
|
41559
|
-
var imported = normalizeImportedDatasets(importFile(fname, importOpts));
|
|
41560
|
-
// check if dataset contains non-topological paths
|
|
41561
|
-
// TODO: may also need to rebuild topology if multiple topojson files are merged
|
|
41562
|
-
imported.forEach(function(dataset) {
|
|
41563
|
-
if (dataset.arcs && dataset.arcs.size() > 0 && dataset.info.input_formats[0] != 'topojson') {
|
|
41564
|
-
unbuiltTopology = true;
|
|
41565
|
-
}
|
|
41566
|
-
memo.push(dataset);
|
|
41567
|
-
});
|
|
41568
|
-
return memo;
|
|
41569
|
-
}, []);
|
|
41570
|
-
var combined = mergeDatasets(datasets);
|
|
41571
|
-
// Build topology, if needed
|
|
41572
|
-
// TODO: consider updating topology of TopoJSON files instead of concatenating arcs
|
|
41573
|
-
// (but problem of mismatched coordinates due to quantization in input files.)
|
|
41574
|
-
if (unbuiltTopology && !opts.no_topology) {
|
|
41575
|
-
cleanPathsAfterImport(combined, opts);
|
|
41576
|
-
buildTopology(combined);
|
|
41577
|
-
}
|
|
41578
|
-
return combined;
|
|
42985
|
+
return input;
|
|
41579
42986
|
}
|
|
41580
42987
|
|
|
42988
|
+
// Import multiple files to a single dataset.
|
|
41581
42989
|
async function importFilesTogetherAsync(files, opts) {
|
|
41582
42990
|
var unbuiltTopology = false;
|
|
41583
42991
|
var datasets = [];
|
|
@@ -41585,7 +42993,7 @@ ${svg}
|
|
|
41585
42993
|
for (var fname of files) {
|
|
41586
42994
|
// import without topology or snapping
|
|
41587
42995
|
var importOpts = utils.defaults({no_topology: true, snap: false, snap_interval: null, files: [fname]}, opts);
|
|
41588
|
-
var imported =
|
|
42996
|
+
var imported = await importDatasetsFromFile(fname, importOpts);
|
|
41589
42997
|
imported.forEach(function(dataset) {
|
|
41590
42998
|
if (dataset.arcs && dataset.arcs.size() > 0 && dataset.info.input_formats[0] != 'topojson') {
|
|
41591
42999
|
unbuiltTopology = true;
|
|
@@ -41647,6 +43055,10 @@ ${svg}
|
|
|
41647
43055
|
return Array.isArray(datasetOrArray) ? datasetOrArray : [datasetOrArray];
|
|
41648
43056
|
}
|
|
41649
43057
|
|
|
43058
|
+
function denormalizeImportedDatasets(datasets) {
|
|
43059
|
+
return datasets.length == 1 ? datasets[0] : datasets;
|
|
43060
|
+
}
|
|
43061
|
+
|
|
41650
43062
|
function normalizeImportedTarget(datasets) {
|
|
41651
43063
|
if (datasets.length == 1) return datasets[0];
|
|
41652
43064
|
return {
|
|
@@ -41746,9 +43158,9 @@ ${svg}
|
|
|
41746
43158
|
|
|
41747
43159
|
var FileImport = /*#__PURE__*/Object.freeze({
|
|
41748
43160
|
__proto__: null,
|
|
43161
|
+
importDatasetsFromFile: importDatasetsFromFile,
|
|
41749
43162
|
importFile: importFile,
|
|
41750
43163
|
importFileAsync: importFileAsync,
|
|
41751
|
-
importFilesTogether: importFilesTogether,
|
|
41752
43164
|
importFilesTogetherAsync: importFilesTogetherAsync,
|
|
41753
43165
|
replaceImportFile: replaceImportFile
|
|
41754
43166
|
});
|
|
@@ -41778,31 +43190,37 @@ ${svg}
|
|
|
41778
43190
|
return /[$][{]/.test(name);
|
|
41779
43191
|
}
|
|
41780
43192
|
|
|
41781
|
-
function
|
|
43193
|
+
async function findCommandSourceAsync(sourceName, catalog, opts) {
|
|
41782
43194
|
var source = catalog.findSingleLayer(sourceName);
|
|
41783
|
-
var
|
|
43195
|
+
var sourceDatasets;
|
|
41784
43196
|
if (!source) {
|
|
41785
|
-
//
|
|
41786
|
-
|
|
41787
|
-
|
|
41788
|
-
// clip/erase -- topology is built later, when datasets are combined
|
|
41789
|
-
sourceDataset = importFile(sourceName, utils.defaults({no_topology: true}, opts));
|
|
41790
|
-
if (!sourceDataset) {
|
|
41791
|
-
stop$1(utils.format('Unable to find source [%s]', sourceName));
|
|
41792
|
-
} else if (sourceDataset.layers.length > 1) {
|
|
41793
|
-
stop$1('Multiple-layer sources are not supported');
|
|
41794
|
-
}
|
|
41795
|
-
// mark as disposable to indicate that data can be mutated
|
|
41796
|
-
source = {dataset: sourceDataset, layer: sourceDataset.layers[0], disposable: true};
|
|
43197
|
+
// Source-file topology is built later if it is needed by the command.
|
|
43198
|
+
sourceDatasets = await importDatasetsFromFile(sourceName, utils.defaults({no_topology: true}, opts));
|
|
43199
|
+
source = getImportedSource(sourceDatasets, sourceName);
|
|
41797
43200
|
}
|
|
41798
43201
|
return source;
|
|
41799
43202
|
}
|
|
41800
43203
|
|
|
43204
|
+
function getImportedSource(sourceDatasets, sourceName) {
|
|
43205
|
+
if (sourceDatasets.length != 1) {
|
|
43206
|
+
if (sourceDatasets.length > 1) {
|
|
43207
|
+
stop$1('Multiple-dataset sources are not supported');
|
|
43208
|
+
}
|
|
43209
|
+
stop$1(utils.format('Unable to find source [%s]', sourceName));
|
|
43210
|
+
}
|
|
43211
|
+
var sourceDataset = sourceDatasets[0];
|
|
43212
|
+
if (sourceDataset.layers.length > 1) {
|
|
43213
|
+
stop$1('Multiple-layer sources are not supported');
|
|
43214
|
+
}
|
|
43215
|
+
// mark as disposable to indicate that data can be mutated
|
|
43216
|
+
return {dataset: sourceDataset, layer: sourceDataset.layers[0], disposable: true};
|
|
43217
|
+
}
|
|
43218
|
+
|
|
41801
43219
|
var SourceUtils = /*#__PURE__*/Object.freeze({
|
|
41802
43220
|
__proto__: null,
|
|
41803
43221
|
convertInterpolatedName: convertInterpolatedName,
|
|
41804
43222
|
convertSourceName: convertSourceName,
|
|
41805
|
-
|
|
43223
|
+
findCommandSourceAsync: findCommandSourceAsync
|
|
41806
43224
|
});
|
|
41807
43225
|
|
|
41808
43226
|
// Catalog contains zero or more multi-layer datasets
|
|
@@ -43657,6 +45075,13 @@ ${svg}
|
|
|
43657
45075
|
return new GeographicLib.Geodesic.Geodesic(P.a, f);
|
|
43658
45076
|
}
|
|
43659
45077
|
|
|
45078
|
+
function getGeodesicDistanceFunction(P) {
|
|
45079
|
+
var geod = getGeodesic(P);
|
|
45080
|
+
return function(lng, lat, lng2, lat2) {
|
|
45081
|
+
return geod.Inverse(lat, lng, lat2, lng2).s12;
|
|
45082
|
+
};
|
|
45083
|
+
}
|
|
45084
|
+
|
|
43660
45085
|
function interpolatePoint2D(ax, ay, bx, by, k) {
|
|
43661
45086
|
var j = 1 - k;
|
|
43662
45087
|
return [ax * j + bx * k, ay * j + by * k];
|
|
@@ -43759,6 +45184,7 @@ ${svg}
|
|
|
43759
45184
|
bearingDegrees2D: bearingDegrees2D,
|
|
43760
45185
|
getBearingFunction: getBearingFunction,
|
|
43761
45186
|
getFastGeodeticSegmentFunction: getFastGeodeticSegmentFunction,
|
|
45187
|
+
getGeodesicDistanceFunction: getGeodesicDistanceFunction,
|
|
43762
45188
|
getGeodeticSegmentFunction: getGeodeticSegmentFunction,
|
|
43763
45189
|
getInterpolationFunction: getInterpolationFunction,
|
|
43764
45190
|
getPlanarSegmentEndpoint: getPlanarSegmentEndpoint,
|
|
@@ -45199,7 +46625,7 @@ ${svg}
|
|
|
45199
46625
|
|
|
45200
46626
|
function stopIfBufferReachesPole(shape, dist) {
|
|
45201
46627
|
var maxAbsLat = 0;
|
|
45202
|
-
var angularDist = dist / R$3 * R2D$
|
|
46628
|
+
var angularDist = dist / R$3 * R2D$7;
|
|
45203
46629
|
(shape || []).forEach(function(path) {
|
|
45204
46630
|
latLngPathIter.init(path);
|
|
45205
46631
|
while (latLngPathIter.hasNext()) {
|
|
@@ -47316,12 +48742,12 @@ ${svg}
|
|
|
47316
48742
|
}
|
|
47317
48743
|
|
|
47318
48744
|
function projectBufferPoint(x, y, spherical) {
|
|
47319
|
-
return spherical ? [x * D2R$
|
|
48745
|
+
return spherical ? [x * D2R$8 * R$3, Math.log(Math.tan(Math.PI / 4 + y * D2R$8 / 2)) * R$3] :
|
|
47320
48746
|
[x, y];
|
|
47321
48747
|
}
|
|
47322
48748
|
|
|
47323
48749
|
function unprojectBufferPoint(x, y, spherical) {
|
|
47324
|
-
return spherical ? [x / (D2R$
|
|
48750
|
+
return spherical ? [x / (D2R$8 * R$3), (2 * Math.atan(Math.exp(y / R$3)) - Math.PI / 2) / (D2R$8)] :
|
|
47325
48751
|
[x, y];
|
|
47326
48752
|
}
|
|
47327
48753
|
|
|
@@ -51992,7 +53418,7 @@ ${svg}
|
|
|
51992
53418
|
var maxAbsLat = Math.max(Math.abs(bounds.ymin), Math.abs(bounds.ymax));
|
|
51993
53419
|
var maxPositiveDistance = getMaxPositiveBufferDistance(lyr, dataset, opts);
|
|
51994
53420
|
if (!(maxPositiveDistance > 0)) return false;
|
|
51995
|
-
return maxAbsLat + maxPositiveDistance / R$3 * R2D$
|
|
53421
|
+
return maxAbsLat + maxPositiveDistance / R$3 * R2D$7 >= 90 - POLAR_BUFFER_MARGIN_DEGREES;
|
|
51996
53422
|
}
|
|
51997
53423
|
|
|
51998
53424
|
function getMaxPositiveBufferDistance(lyr, dataset, opts) {
|
|
@@ -53244,7 +54670,7 @@ ${svg}
|
|
|
53244
54670
|
}
|
|
53245
54671
|
|
|
53246
54672
|
function getCoordinateDistance(distance, arcs) {
|
|
53247
|
-
return arcs.isPlanar() ? distance : distance / R$3 * R2D$
|
|
54673
|
+
return arcs.isPlanar() ? distance : distance / R$3 * R2D$7;
|
|
53248
54674
|
}
|
|
53249
54675
|
|
|
53250
54676
|
// @shapeIndex: chunk-bounds index of the source shape (see buildShapeSegmentIndex)
|
|
@@ -53913,7 +55339,7 @@ ${svg}
|
|
|
53913
55339
|
// depending on parameters
|
|
53914
55340
|
if (inList(P, 'cassini,gnom,bertin1953,chamb,ob_tran,tpeqd,healpix,rhealpix,' +
|
|
53915
55341
|
'ocea,omerc,tmerc,etmerc,nicol,dymaxion,dymaxion2,butterfly,butterfly2,' +
|
|
53916
|
-
'cahill_keyes')) {
|
|
55342
|
+
'cahill_keyes,narukawa2022,markley,calm')) {
|
|
53917
55343
|
return false;
|
|
53918
55344
|
}
|
|
53919
55345
|
if (isAzimuthal(P)) {
|
|
@@ -53965,16 +55391,16 @@ ${svg}
|
|
|
53965
55391
|
}
|
|
53966
55392
|
|
|
53967
55393
|
function getRotationFunction2(rotation, inv) {
|
|
53968
|
-
var a = (rotation[0] || 0) * D2R$
|
|
53969
|
-
b = (rotation[1] || 0) * D2R$
|
|
53970
|
-
c = (rotation[2] || 0) * D2R$
|
|
55394
|
+
var a = (rotation[0] || 0) * D2R$8,
|
|
55395
|
+
b = (rotation[1] || 0) * D2R$8,
|
|
55396
|
+
c = (rotation[2] || 0) * D2R$8;
|
|
53971
55397
|
return function(p) {
|
|
53972
|
-
p[0] *= D2R$
|
|
53973
|
-
p[1] *= D2R$
|
|
55398
|
+
p[0] *= D2R$8;
|
|
55399
|
+
p[1] *= D2R$8;
|
|
53974
55400
|
var rotate = inv ? rotatePointInv : rotatePoint;
|
|
53975
55401
|
rotate(p, a, b, c);
|
|
53976
|
-
p[0] *= R2D$
|
|
53977
|
-
p[1] *= R2D$
|
|
55402
|
+
p[0] *= R2D$7;
|
|
55403
|
+
p[1] *= R2D$7;
|
|
53978
55404
|
return p;
|
|
53979
55405
|
};
|
|
53980
55406
|
}
|
|
@@ -54454,7 +55880,19 @@ ${svg}
|
|
|
54454
55880
|
type: o.type,
|
|
54455
55881
|
coordinates: rotatePath(o.coordinates, lon0)
|
|
54456
55882
|
};
|
|
54457
|
-
})
|
|
55883
|
+
}),
|
|
55884
|
+
findRegion: function(lon, lat) {
|
|
55885
|
+
return findClassicRegion(defn, normalizeLongitude(lon - lon0), lat);
|
|
55886
|
+
},
|
|
55887
|
+
findTransitionRegion: function(lon, lat) {
|
|
55888
|
+
return findClassicRegion(defn, normalizeLongitude(lon - lon0), lat);
|
|
55889
|
+
},
|
|
55890
|
+
constrainRegionPoint: function(lon, lat, regionId) {
|
|
55891
|
+
return constrainClassicRegionPoint(defn, lon0, lon, lat, regionId);
|
|
55892
|
+
},
|
|
55893
|
+
getRegionBoundary: function(regionId) {
|
|
55894
|
+
return getClassicRegionBoundary(defn, lon0, regionId, 0.5);
|
|
55895
|
+
}
|
|
54458
55896
|
};
|
|
54459
55897
|
}
|
|
54460
55898
|
|
|
@@ -54484,6 +55922,68 @@ ${svg}
|
|
|
54484
55922
|
};
|
|
54485
55923
|
}
|
|
54486
55924
|
|
|
55925
|
+
function findClassicRegion(defn, lon, lat) {
|
|
55926
|
+
for (var i = 0; i < defn.regions.length; i++) {
|
|
55927
|
+
var region = defn.regions[i];
|
|
55928
|
+
var ring = region.boundary;
|
|
55929
|
+
if (lon >= ring[0][0] && lon <= ring[2][0] &&
|
|
55930
|
+
lat >= ring[0][1] && lat <= ring[2][1]) {
|
|
55931
|
+
return region.id;
|
|
55932
|
+
}
|
|
55933
|
+
}
|
|
55934
|
+
return null;
|
|
55935
|
+
}
|
|
55936
|
+
|
|
55937
|
+
function constrainClassicRegionPoint(defn, lon0, lon, lat, regionId) {
|
|
55938
|
+
var region = findRegionById(defn, regionId);
|
|
55939
|
+
if (!region) return null;
|
|
55940
|
+
var ring = region.boundary;
|
|
55941
|
+
var xmin = ring[0][0];
|
|
55942
|
+
var ymin = ring[0][1];
|
|
55943
|
+
var xmax = ring[2][0];
|
|
55944
|
+
var ymax = ring[2][1];
|
|
55945
|
+
var localLon = normalizeLongitude(lon - lon0);
|
|
55946
|
+
var x = Math.max(xmin, Math.min(xmax, localLon));
|
|
55947
|
+
var y = Math.max(ymin, Math.min(ymax, lat));
|
|
55948
|
+
var cx = (xmin + xmax) / 2;
|
|
55949
|
+
var cy = (ymin + ymax) / 2;
|
|
55950
|
+
var inset = 1e-8;
|
|
55951
|
+
if (x == xmin || x == xmax) x += (cx - x) * inset;
|
|
55952
|
+
if (y == ymin || y == ymax) y += (cy - y) * inset;
|
|
55953
|
+
return [normalizeLongitude(x + lon0), y];
|
|
55954
|
+
}
|
|
55955
|
+
|
|
55956
|
+
function getClassicRegionBoundary(defn, lon0, regionId, interval) {
|
|
55957
|
+
var region = findRegionById(defn, regionId);
|
|
55958
|
+
if (!region) return null;
|
|
55959
|
+
var ring = region.boundary;
|
|
55960
|
+
var corners = [ring[0], ring[1], ring[2], ring[3], ring[0]];
|
|
55961
|
+
var points = [];
|
|
55962
|
+
for (var i = 1; i < corners.length; i++) {
|
|
55963
|
+
var a = corners[i - 1];
|
|
55964
|
+
var b = corners[i];
|
|
55965
|
+
var n = Math.max(1, Math.ceil(Math.max(
|
|
55966
|
+
Math.abs(b[0] - a[0]),
|
|
55967
|
+
Math.abs(b[1] - a[1])
|
|
55968
|
+
) / interval));
|
|
55969
|
+
for (var j = 0; j < n; j++) {
|
|
55970
|
+
points.push([
|
|
55971
|
+
normalizeLongitude(a[0] + (b[0] - a[0]) * j / n + lon0),
|
|
55972
|
+
a[1] + (b[1] - a[1]) * j / n
|
|
55973
|
+
]);
|
|
55974
|
+
}
|
|
55975
|
+
}
|
|
55976
|
+
points.push(points[0].concat());
|
|
55977
|
+
return points;
|
|
55978
|
+
}
|
|
55979
|
+
|
|
55980
|
+
function findRegionById(defn, regionId) {
|
|
55981
|
+
for (var i = 0; i < defn.regions.length; i++) {
|
|
55982
|
+
if (defn.regions[i].id == regionId) return defn.regions[i];
|
|
55983
|
+
}
|
|
55984
|
+
return null;
|
|
55985
|
+
}
|
|
55986
|
+
|
|
54487
55987
|
function cutSeam(coordinates) {
|
|
54488
55988
|
return {
|
|
54489
55989
|
type: 'cut',
|
|
@@ -55190,6 +56690,13 @@ ${svg}
|
|
|
55190
56690
|
|
|
55191
56691
|
var DEFAULT_MESH_INTERVAL = 32;
|
|
55192
56692
|
var DEFAULT_MAX_EDGE_FACTOR = 20;
|
|
56693
|
+
var DEFAULT_TOPOLOGY_MIN_CELL_SIZE = 0.5;
|
|
56694
|
+
var MAX_TOPOLOGY_SUBDIVISION_DEPTH = 12;
|
|
56695
|
+
var TOPOLOGY_SAMPLE_STEPS = 4;
|
|
56696
|
+
var TOPOLOGY_VERTEX_INSET = 1e-7;
|
|
56697
|
+
var PIECE_SAMPLE_STEPS = 4;
|
|
56698
|
+
var EXPANDED_FACET_MAX_EDGE_DEGREES = 2;
|
|
56699
|
+
var EXPANDED_FACET_MAX_CLIP_ERROR = 0.02;
|
|
55193
56700
|
|
|
55194
56701
|
function projectRasterGridForward(raster, srcCRS, destCRS, optsArg) {
|
|
55195
56702
|
var opts = optsArg || {};
|
|
@@ -55200,8 +56707,8 @@ ${svg}
|
|
|
55200
56707
|
var mesh, bbox, outSize, outGrid;
|
|
55201
56708
|
validateRasterGridForProjection(grid);
|
|
55202
56709
|
timeStart(timing, 'mesh');
|
|
55203
|
-
mesh =
|
|
55204
|
-
|
|
56710
|
+
mesh = buildRasterProjectionMesh(grid, srcCRS, destCRS, transform, interval, opts);
|
|
56711
|
+
classifyRasterMesh(mesh, opts);
|
|
55205
56712
|
timeEnd(timing, 'mesh');
|
|
55206
56713
|
bbox = opts.output_bbox || opts.outputBbox || getProjectedMeshBBox(mesh);
|
|
55207
56714
|
if (!bbox) stop$1('Unable to project raster layer');
|
|
@@ -55209,12 +56716,17 @@ ${svg}
|
|
|
55209
56716
|
outGrid = createProjectedRasterGrid(grid, raster, bbox, outSize.width, outSize.height, opts);
|
|
55210
56717
|
timeStart(timing, 'rasterize');
|
|
55211
56718
|
rasterizeProjectedMesh(grid, outGrid, mesh, getRasterProjectionSampleMethod(raster, opts));
|
|
56719
|
+
if (mesh.fillOutputCoverage) {
|
|
56720
|
+
fillProjectedRasterCoverage(outGrid);
|
|
56721
|
+
} else {
|
|
56722
|
+
fillIsolatedProjectedRasterHoles(outGrid);
|
|
56723
|
+
}
|
|
55212
56724
|
timeEnd(timing, 'rasterize');
|
|
55213
56725
|
if (timing) {
|
|
55214
56726
|
timing.outputWidth = outGrid.width;
|
|
55215
56727
|
timing.outputHeight = outGrid.height;
|
|
55216
56728
|
timing.meshVertices = mesh.vertices.length;
|
|
55217
|
-
timing.meshCells = mesh.cells.length;
|
|
56729
|
+
timing.meshCells = mesh.triangles ? mesh.triangles.length : mesh.cells.length;
|
|
55218
56730
|
timing.meshSkippedCells = mesh.skippedCellCount;
|
|
55219
56731
|
}
|
|
55220
56732
|
return outGrid;
|
|
@@ -55251,17 +56763,34 @@ ${svg}
|
|
|
55251
56763
|
var transform = getProjTransform2(srcCRS, destCRS);
|
|
55252
56764
|
var mesh, bbox;
|
|
55253
56765
|
validateRasterGridForProjection(grid);
|
|
55254
|
-
mesh =
|
|
55255
|
-
|
|
56766
|
+
mesh = buildRasterProjectionMesh(grid, srcCRS, destCRS, transform, interval, opts);
|
|
56767
|
+
classifyRasterMesh(mesh, opts);
|
|
55256
56768
|
bbox = getProjectedMeshBBox(mesh);
|
|
55257
56769
|
return bbox;
|
|
55258
56770
|
}
|
|
55259
56771
|
|
|
55260
56772
|
function getProjectedRasterMeshBBox(mesh, optsArg) {
|
|
55261
|
-
|
|
56773
|
+
classifyRasterMesh(mesh, optsArg || {});
|
|
55262
56774
|
return getProjectedMeshBBox(mesh);
|
|
55263
56775
|
}
|
|
55264
56776
|
|
|
56777
|
+
function buildRasterProjectionMesh(grid, srcCRS, destCRS, transform, interval, opts) {
|
|
56778
|
+
var topology = getProjectionTopology(destCRS);
|
|
56779
|
+
if (topology && (topology.raster_source_regions ||
|
|
56780
|
+
topology.raster_spherical_regions)) {
|
|
56781
|
+
return buildExpandedFacetRasterMesh(
|
|
56782
|
+
grid, srcCRS, destCRS, interval, topology);
|
|
56783
|
+
}
|
|
56784
|
+
if (topology && (topology.projectRasterRegion ||
|
|
56785
|
+
topology.projectRegion || topology.constrainRegionPoint)) {
|
|
56786
|
+
return buildPiecewiseProjectedRasterMesh(grid, srcCRS, destCRS, interval, topology);
|
|
56787
|
+
}
|
|
56788
|
+
if (topology && (topology.findTransitionRegion || topology.findRegion)) {
|
|
56789
|
+
return buildTopologyAwareProjectedRasterMesh(grid, srcCRS, destCRS, interval, opts);
|
|
56790
|
+
}
|
|
56791
|
+
return buildProjectedRasterMesh(grid, transform, interval);
|
|
56792
|
+
}
|
|
56793
|
+
|
|
55265
56794
|
function buildProjectedRasterMesh(grid, transform, interval) {
|
|
55266
56795
|
var xs = getMeshStops(grid.width, interval);
|
|
55267
56796
|
var ys = getMeshStops(grid.height, interval);
|
|
@@ -55278,6 +56807,494 @@ ${svg}
|
|
|
55278
56807
|
};
|
|
55279
56808
|
}
|
|
55280
56809
|
|
|
56810
|
+
function buildPiecewiseProjectedRasterMesh(grid, srcCRS, destCRS, interval, topology) {
|
|
56811
|
+
var wgs84 = parseCrsString$1('wgs84');
|
|
56812
|
+
var toGeographic = getProjTransform2(srcCRS, wgs84);
|
|
56813
|
+
var fromGeographic = getProjTransform2(wgs84, srcCRS);
|
|
56814
|
+
var toDestination = getProjTransform2(wgs84, destCRS);
|
|
56815
|
+
interval = Math.min(interval, topology.raster_mesh_interval || interval);
|
|
56816
|
+
var xs = getMeshStops(grid.width, interval);
|
|
56817
|
+
var ys = getMeshStops(grid.height, interval);
|
|
56818
|
+
var regions = topology.raster_regions || topology.regions;
|
|
56819
|
+
var mesh = {
|
|
56820
|
+
xs: xs,
|
|
56821
|
+
ys: ys,
|
|
56822
|
+
vertices: [],
|
|
56823
|
+
cells: [],
|
|
56824
|
+
topologyAware: true,
|
|
56825
|
+
subdivisionSkippedCellCount: 0,
|
|
56826
|
+
fillRegionMask: topology.fill_raster_mask,
|
|
56827
|
+
fillOutputCoverage: topology.fill_raster_coverage,
|
|
56828
|
+
projectedRegions: getProjectedRasterRegions(
|
|
56829
|
+
topology, regions, destCRS, toDestination)
|
|
56830
|
+
};
|
|
56831
|
+
var context = {
|
|
56832
|
+
grid: grid,
|
|
56833
|
+
topology: topology,
|
|
56834
|
+
destCRS: destCRS,
|
|
56835
|
+
toGeographic: toGeographic,
|
|
56836
|
+
fromGeographic: fromGeographic,
|
|
56837
|
+
toDestination: toDestination,
|
|
56838
|
+
findRegion: topology.findRasterRegion || topology.findRegion,
|
|
56839
|
+
projectRegion: topology.projectRasterRegion || topology.projectRegion,
|
|
56840
|
+
pieceHalo: topology.raster_cell_halo === false ? 0 : interval,
|
|
56841
|
+
mesh: mesh
|
|
56842
|
+
};
|
|
56843
|
+
for (var y = 0; y < ys.length - 1; y++) {
|
|
56844
|
+
for (var x = 0; x < xs.length - 1; x++) {
|
|
56845
|
+
appendPiecewiseMeshCells(context, xs[x], ys[y], xs[x + 1], ys[y + 1]);
|
|
56846
|
+
}
|
|
56847
|
+
}
|
|
56848
|
+
return mesh;
|
|
56849
|
+
}
|
|
56850
|
+
|
|
56851
|
+
function buildExpandedFacetRasterMesh(grid, srcCRS, destCRS, interval, topology) {
|
|
56852
|
+
var wgs84 = parseCrsString$1('wgs84');
|
|
56853
|
+
var fromGeographic = getProjTransform2(wgs84, srcCRS);
|
|
56854
|
+
var regions = topology.raster_regions;
|
|
56855
|
+
var mesh = {
|
|
56856
|
+
vertices: [],
|
|
56857
|
+
cells: [],
|
|
56858
|
+
triangles: [],
|
|
56859
|
+
topologyAware: true,
|
|
56860
|
+
subdivisionSkippedCellCount: 0,
|
|
56861
|
+
fillRegionMask: topology.fill_raster_mask,
|
|
56862
|
+
fillOutputCoverage: topology.fill_raster_coverage,
|
|
56863
|
+
projectedRegions: getProjectedRasterRegions(
|
|
56864
|
+
topology, regions, destCRS, getProjTransform2(wgs84, destCRS)),
|
|
56865
|
+
sourceWrapX: isLatLngCRS(srcCRS) &&
|
|
56866
|
+
Math.abs(grid.bbox[2] - grid.bbox[0] - 360) < 1e-3
|
|
56867
|
+
};
|
|
56868
|
+
var sourceRegions = topology.raster_source_regions ||
|
|
56869
|
+
topology.raster_spherical_regions;
|
|
56870
|
+
var piecesBySourceRegion = new Map();
|
|
56871
|
+
regions.forEach(function(region) {
|
|
56872
|
+
var key = getRasterSourceRegionKey(region);
|
|
56873
|
+
var pieces = piecesBySourceRegion.get(key) || [];
|
|
56874
|
+
pieces.push(region);
|
|
56875
|
+
piecesBySourceRegion.set(key, pieces);
|
|
56876
|
+
});
|
|
56877
|
+
var context = {
|
|
56878
|
+
grid: grid,
|
|
56879
|
+
topology: topology,
|
|
56880
|
+
destCRS: destCRS,
|
|
56881
|
+
fromGeographic: fromGeographic,
|
|
56882
|
+
mesh: mesh
|
|
56883
|
+
};
|
|
56884
|
+
sourceRegions.forEach(function(region) {
|
|
56885
|
+
var boundary = region.boundary;
|
|
56886
|
+
var pieces = piecesBySourceRegion.get(getRasterSourceRegionKey(region));
|
|
56887
|
+
var triangles = [];
|
|
56888
|
+
var end = pointsEqual2D(boundary[0], boundary[boundary.length - 1]) ?
|
|
56889
|
+
boundary.length - 1 : boundary.length;
|
|
56890
|
+
for (var i = 1; i < end - 1; i++) {
|
|
56891
|
+
triangles.push([boundary[0], boundary[i], boundary[i + 1]]);
|
|
56892
|
+
}
|
|
56893
|
+
triangles.forEach(function(triangle) {
|
|
56894
|
+
var depth = getSphericalTriangleSubdivisionDepth(
|
|
56895
|
+
triangle, EXPANDED_FACET_MAX_EDGE_DEGREES);
|
|
56896
|
+
subdivideSphericalRasterTriangle(
|
|
56897
|
+
context, triangle, region, pieces, depth);
|
|
56898
|
+
});
|
|
56899
|
+
});
|
|
56900
|
+
return mesh;
|
|
56901
|
+
}
|
|
56902
|
+
|
|
56903
|
+
function getRasterSourceRegionKey(region) {
|
|
56904
|
+
if (region.source_region != null) return String(region.source_region);
|
|
56905
|
+
if (region.facet != null && region.sector != null) {
|
|
56906
|
+
return region.facet + ':' + region.sector;
|
|
56907
|
+
}
|
|
56908
|
+
return String(region.id);
|
|
56909
|
+
}
|
|
56910
|
+
|
|
56911
|
+
function pointsEqual2D(a, b) {
|
|
56912
|
+
return a && b && Math.abs(a[0] - b[0]) < 1e-10 &&
|
|
56913
|
+
Math.abs(a[1] - b[1]) < 1e-10;
|
|
56914
|
+
}
|
|
56915
|
+
|
|
56916
|
+
function getSphericalTriangleSubdivisionDepth(triangle, maxDegrees) {
|
|
56917
|
+
var max = Math.max(
|
|
56918
|
+
sphericalPointDistance(triangle[0], triangle[1]),
|
|
56919
|
+
sphericalPointDistance(triangle[1], triangle[2]),
|
|
56920
|
+
sphericalPointDistance(triangle[2], triangle[0])
|
|
56921
|
+
);
|
|
56922
|
+
return Math.max(0, Math.ceil(Math.log(max / maxDegrees) / Math.LN2));
|
|
56923
|
+
}
|
|
56924
|
+
|
|
56925
|
+
function subdivideSphericalRasterTriangle(context, triangle, region, pieces, depth) {
|
|
56926
|
+
if (depth > 0) {
|
|
56927
|
+
var ab = sphericalPointMidpoint(triangle[0], triangle[1]);
|
|
56928
|
+
var bc = sphericalPointMidpoint(triangle[1], triangle[2]);
|
|
56929
|
+
var ca = sphericalPointMidpoint(triangle[2], triangle[0]);
|
|
56930
|
+
subdivideSphericalRasterTriangle(
|
|
56931
|
+
context, [triangle[0], ab, ca], region, pieces, depth - 1);
|
|
56932
|
+
subdivideSphericalRasterTriangle(
|
|
56933
|
+
context, [ab, triangle[1], bc], region, pieces, depth - 1);
|
|
56934
|
+
subdivideSphericalRasterTriangle(
|
|
56935
|
+
context, [ca, bc, triangle[2]], region, pieces, depth - 1);
|
|
56936
|
+
subdivideSphericalRasterTriangle(
|
|
56937
|
+
context, [ab, bc, ca], region, pieces, depth - 1);
|
|
56938
|
+
return;
|
|
56939
|
+
}
|
|
56940
|
+
var rawVertices = triangle.map(function(lonlat) {
|
|
56941
|
+
return projectSphericalRawVertex(context, lonlat, region);
|
|
56942
|
+
});
|
|
56943
|
+
normalizeWrappedTrianglePixels(
|
|
56944
|
+
rawVertices, context.grid.width, context.mesh.sourceWrapX);
|
|
56945
|
+
pieces.forEach(function(piece) {
|
|
56946
|
+
var polygon = context.topology.clipRasterRegionPolygon(
|
|
56947
|
+
rawVertices, piece.id);
|
|
56948
|
+
if (!rasterPiecePolygonIsAccurate(
|
|
56949
|
+
context.topology, polygon, piece.id)) return;
|
|
56950
|
+
polygon.forEach(function(vertex) {
|
|
56951
|
+
var p = scaleRawProjectionPoint(
|
|
56952
|
+
context.destCRS, [vertex.x, vertex.y]);
|
|
56953
|
+
vertex.x = p[0];
|
|
56954
|
+
vertex.y = p[1];
|
|
56955
|
+
});
|
|
56956
|
+
for (var i = 1; i < polygon.length - 1; i++) {
|
|
56957
|
+
var vertices = [polygon[0], polygon[i], polygon[i + 1]];
|
|
56958
|
+
context.mesh.vertices.push(vertices[0], vertices[1], vertices[2]);
|
|
56959
|
+
context.mesh.triangles.push({
|
|
56960
|
+
a: vertices[0],
|
|
56961
|
+
b: vertices[1],
|
|
56962
|
+
c: vertices[2],
|
|
56963
|
+
region: piece.id,
|
|
56964
|
+
valid: vertices.every(vertexIsValid)
|
|
56965
|
+
});
|
|
56966
|
+
}
|
|
56967
|
+
});
|
|
56968
|
+
}
|
|
56969
|
+
|
|
56970
|
+
function projectSphericalRawVertex(context, lonlat, region) {
|
|
56971
|
+
var sourceXY = context.fromGeographic(lonlat[0], lonlat[1]);
|
|
56972
|
+
var sourcePixel = sourceXY &&
|
|
56973
|
+
rasterMapXYToPixel(context.grid, sourceXY[0], sourceXY[1]);
|
|
56974
|
+
var p = context.topology.projectRasterSourceRegion ?
|
|
56975
|
+
context.topology.projectRasterSourceRegion(
|
|
56976
|
+
lonlat[0], lonlat[1], region.id) :
|
|
56977
|
+
context.topology.projectRasterSector(
|
|
56978
|
+
lonlat[0], lonlat[1], region.facet, region.sector);
|
|
56979
|
+
return {
|
|
56980
|
+
sx: sourcePixel ? sourcePixel[0] : NaN,
|
|
56981
|
+
sy: sourcePixel ? sourcePixel[1] : NaN,
|
|
56982
|
+
x: p && isFinite(p[0]) ? p[0] : NaN,
|
|
56983
|
+
y: p && isFinite(p[1]) ? p[1] : NaN,
|
|
56984
|
+
lon: lonlat[0],
|
|
56985
|
+
lat: lonlat[1]
|
|
56986
|
+
};
|
|
56987
|
+
}
|
|
56988
|
+
|
|
56989
|
+
function rasterPiecePolygonIsAccurate(topology, polygon, regionId) {
|
|
56990
|
+
// A triangle that crosses a forced sector discontinuity can yield invalid
|
|
56991
|
+
// interpolated clip vertices. Adjacent triangles cover the rejected sliver.
|
|
56992
|
+
return polygon.every(function(vertex) {
|
|
56993
|
+
var p = topology.projectRasterRegion(
|
|
56994
|
+
vertex.lon, vertex.lat, regionId);
|
|
56995
|
+
return p && Math.hypot(vertex.x - p[0], vertex.y - p[1]) <
|
|
56996
|
+
EXPANDED_FACET_MAX_CLIP_ERROR;
|
|
56997
|
+
});
|
|
56998
|
+
}
|
|
56999
|
+
|
|
57000
|
+
function normalizeWrappedTrianglePixels(vertices, width, wrap) {
|
|
57001
|
+
if (!wrap) return;
|
|
57002
|
+
var xmin = Math.min(vertices[0].sx, vertices[1].sx, vertices[2].sx);
|
|
57003
|
+
var xmax = Math.max(vertices[0].sx, vertices[1].sx, vertices[2].sx);
|
|
57004
|
+
if (xmax - xmin <= width / 2) return;
|
|
57005
|
+
vertices.forEach(function(vertex) {
|
|
57006
|
+
if (vertex.sx < width / 2) vertex.sx += width;
|
|
57007
|
+
});
|
|
57008
|
+
}
|
|
57009
|
+
|
|
57010
|
+
function sphericalPointMidpoint(a, b) {
|
|
57011
|
+
var av = lonLatToVector(a);
|
|
57012
|
+
var bv = lonLatToVector(b);
|
|
57013
|
+
return vectorToLonLat(normalizeVector3([
|
|
57014
|
+
av[0] + bv[0],
|
|
57015
|
+
av[1] + bv[1],
|
|
57016
|
+
av[2] + bv[2]
|
|
57017
|
+
]));
|
|
57018
|
+
}
|
|
57019
|
+
|
|
57020
|
+
function sphericalPointDistance(a, b) {
|
|
57021
|
+
var av = lonLatToVector(a);
|
|
57022
|
+
var bv = lonLatToVector(b);
|
|
57023
|
+
return Math.acos(clamp$1(
|
|
57024
|
+
av[0] * bv[0] + av[1] * bv[1] + av[2] * bv[2], -1, 1
|
|
57025
|
+
)) * 180 / Math.PI;
|
|
57026
|
+
}
|
|
57027
|
+
|
|
57028
|
+
function lonLatToVector(p) {
|
|
57029
|
+
var lam = p[0] * Math.PI / 180;
|
|
57030
|
+
var phi = p[1] * Math.PI / 180;
|
|
57031
|
+
var cosPhi = Math.cos(phi);
|
|
57032
|
+
return [Math.cos(lam) * cosPhi, Math.sin(lam) * cosPhi, Math.sin(phi)];
|
|
57033
|
+
}
|
|
57034
|
+
|
|
57035
|
+
function vectorToLonLat(p) {
|
|
57036
|
+
return [
|
|
57037
|
+
Math.atan2(p[1], p[0]) * 180 / Math.PI,
|
|
57038
|
+
Math.asin(clamp$1(p[2], -1, 1)) * 180 / Math.PI
|
|
57039
|
+
];
|
|
57040
|
+
}
|
|
57041
|
+
|
|
57042
|
+
function normalizeVector3(p) {
|
|
57043
|
+
var k = 1 / Math.hypot(p[0], p[1], p[2]);
|
|
57044
|
+
return [p[0] * k, p[1] * k, p[2] * k];
|
|
57045
|
+
}
|
|
57046
|
+
|
|
57047
|
+
function appendPiecewiseMeshCells(context, x0, y0, x1, y1) {
|
|
57048
|
+
getPieceRegionsInCell(context, x0, y0, x1, y1).forEach(function(regionId) {
|
|
57049
|
+
var v00 = projectPiecewiseMeshVertex(context, x0, y0, regionId);
|
|
57050
|
+
var v10 = projectPiecewiseMeshVertex(context, x1, y0, regionId);
|
|
57051
|
+
var v01 = projectPiecewiseMeshVertex(context, x0, y1, regionId);
|
|
57052
|
+
var v11 = projectPiecewiseMeshVertex(context, x1, y1, regionId);
|
|
57053
|
+
var cell = {
|
|
57054
|
+
v00: v00,
|
|
57055
|
+
v10: v10,
|
|
57056
|
+
v01: v01,
|
|
57057
|
+
v11: v11,
|
|
57058
|
+
region: regionId,
|
|
57059
|
+
valid: vertexIsValid(v00) && vertexIsValid(v10) &&
|
|
57060
|
+
vertexIsValid(v01) && vertexIsValid(v11)
|
|
57061
|
+
};
|
|
57062
|
+
context.mesh.vertices.push(v00, v10, v01, v11);
|
|
57063
|
+
context.mesh.cells.push(cell);
|
|
57064
|
+
});
|
|
57065
|
+
}
|
|
57066
|
+
|
|
57067
|
+
function getPieceRegionsInCell(context, x0, y0, x1, y1) {
|
|
57068
|
+
var ids = [];
|
|
57069
|
+
var halo = context.pieceHalo;
|
|
57070
|
+
samplePieceRegions(context, ids, x0, y0, x1, y1);
|
|
57071
|
+
if (halo > 0) {
|
|
57072
|
+
samplePieceRegions(
|
|
57073
|
+
context,
|
|
57074
|
+
ids,
|
|
57075
|
+
Math.max(0, x0 - halo),
|
|
57076
|
+
Math.max(0, y0 - halo),
|
|
57077
|
+
Math.min(context.grid.width, x1 + halo),
|
|
57078
|
+
Math.min(context.grid.height, y1 + halo)
|
|
57079
|
+
);
|
|
57080
|
+
}
|
|
57081
|
+
return ids;
|
|
57082
|
+
}
|
|
57083
|
+
|
|
57084
|
+
function samplePieceRegions(context, ids, x0, y0, x1, y1) {
|
|
57085
|
+
for (var iy = 0; iy <= PIECE_SAMPLE_STEPS; iy++) {
|
|
57086
|
+
for (var ix = 0; ix <= PIECE_SAMPLE_STEPS; ix++) {
|
|
57087
|
+
var px = x0 + (x1 - x0) * ix / PIECE_SAMPLE_STEPS;
|
|
57088
|
+
var py = y0 + (y1 - y0) * iy / PIECE_SAMPLE_STEPS;
|
|
57089
|
+
var xy = rasterPixelToMapXY(context.grid, px, py);
|
|
57090
|
+
var lonlat = context.toGeographic(xy[0], xy[1]);
|
|
57091
|
+
var id = lonlat && context.findRegion(lonlat[0], lonlat[1]);
|
|
57092
|
+
if (id != null && id !== -1 && ids.indexOf(id) == -1) ids.push(id);
|
|
57093
|
+
}
|
|
57094
|
+
}
|
|
57095
|
+
}
|
|
57096
|
+
|
|
57097
|
+
function projectPiecewiseMeshVertex(context, px, py, regionId) {
|
|
57098
|
+
var xy = rasterPixelToMapXY(context.grid, px, py);
|
|
57099
|
+
var lonlat = context.toGeographic(xy[0], xy[1]);
|
|
57100
|
+
var p, sourcePixel;
|
|
57101
|
+
if (!lonlat) return {sx: px, sy: py, x: NaN, y: NaN};
|
|
57102
|
+
if (context.projectRegion) {
|
|
57103
|
+
p = context.projectRegion(lonlat[0], lonlat[1], regionId);
|
|
57104
|
+
p = scaleRawProjectionPoint(context.destCRS, p);
|
|
57105
|
+
sourcePixel = [px, py];
|
|
57106
|
+
} else {
|
|
57107
|
+
lonlat = context.topology.constrainRegionPoint(lonlat[0], lonlat[1], regionId);
|
|
57108
|
+
xy = lonlat && context.fromGeographic(lonlat[0], lonlat[1]);
|
|
57109
|
+
p = lonlat && context.toDestination(lonlat[0], lonlat[1]);
|
|
57110
|
+
sourcePixel = xy && rasterMapXYToPixel(context.grid, xy[0], xy[1]);
|
|
57111
|
+
}
|
|
57112
|
+
return {
|
|
57113
|
+
sx: sourcePixel ? sourcePixel[0] : px,
|
|
57114
|
+
sy: sourcePixel ? sourcePixel[1] : py,
|
|
57115
|
+
x: p && isFinite(p[0]) ? p[0] : NaN,
|
|
57116
|
+
y: p && isFinite(p[1]) ? p[1] : NaN
|
|
57117
|
+
};
|
|
57118
|
+
}
|
|
57119
|
+
|
|
57120
|
+
function getProjectedRasterRegions(topology, regions, destCRS, toDestination) {
|
|
57121
|
+
return regions.map(function(region) {
|
|
57122
|
+
var boundary;
|
|
57123
|
+
if (region.projected_boundary) {
|
|
57124
|
+
boundary = region.projected_boundary.map(function(p) {
|
|
57125
|
+
return scaleRawProjectionPoint(destCRS, p);
|
|
57126
|
+
});
|
|
57127
|
+
} else {
|
|
57128
|
+
boundary = topology.getRegionBoundary(region.id).map(function(p) {
|
|
57129
|
+
var q = topology.constrainRegionPoint(p[0], p[1], region.id);
|
|
57130
|
+
return toDestination(q[0], q[1]);
|
|
57131
|
+
});
|
|
57132
|
+
}
|
|
57133
|
+
return {
|
|
57134
|
+
id: region.id,
|
|
57135
|
+
boundary: boundary
|
|
57136
|
+
};
|
|
57137
|
+
});
|
|
57138
|
+
}
|
|
57139
|
+
|
|
57140
|
+
function scaleRawProjectionPoint(P, p) {
|
|
57141
|
+
if (!p) return null;
|
|
57142
|
+
return [
|
|
57143
|
+
P.fr_meter * (P.a * p[0] + P.x0),
|
|
57144
|
+
P.fr_meter * (P.a * p[1] + P.y0)
|
|
57145
|
+
];
|
|
57146
|
+
}
|
|
57147
|
+
|
|
57148
|
+
function buildTopologyAwareProjectedRasterMesh(grid, srcCRS, destCRS, interval, optsArg) {
|
|
57149
|
+
var opts = optsArg || {};
|
|
57150
|
+
var topology = getProjectionTopology(destCRS);
|
|
57151
|
+
var findRegion = topology && (topology.findTransitionRegion || topology.findRegion);
|
|
57152
|
+
var wgs84 = parseCrsString$1('wgs84');
|
|
57153
|
+
var toGeographic = getProjTransform2(srcCRS, wgs84);
|
|
57154
|
+
var toDestination = getProjTransform2(wgs84, destCRS);
|
|
57155
|
+
var xs = getMeshStops(grid.width, interval);
|
|
57156
|
+
var ys = getMeshStops(grid.height, interval);
|
|
57157
|
+
var minCellSize = opts.raster_topology_min_cell_size ||
|
|
57158
|
+
opts.rasterTopologyMinCellSize ||
|
|
57159
|
+
DEFAULT_TOPOLOGY_MIN_CELL_SIZE;
|
|
57160
|
+
var mesh = {
|
|
57161
|
+
xs: xs,
|
|
57162
|
+
ys: ys,
|
|
57163
|
+
vertices: [],
|
|
57164
|
+
cells: [],
|
|
57165
|
+
topologyAware: true,
|
|
57166
|
+
subdivisionSkippedCellCount: 0
|
|
57167
|
+
};
|
|
57168
|
+
var context = {
|
|
57169
|
+
grid: grid,
|
|
57170
|
+
findRegion: findRegion,
|
|
57171
|
+
toGeographic: toGeographic,
|
|
57172
|
+
toDestination: toDestination,
|
|
57173
|
+
minCellSize: Math.max(0.01, minCellSize),
|
|
57174
|
+
maxDepth: MAX_TOPOLOGY_SUBDIVISION_DEPTH,
|
|
57175
|
+
mesh: mesh
|
|
57176
|
+
};
|
|
57177
|
+
if (!findRegion) return buildProjectedRasterMesh(grid, getProjTransform2(srcCRS, destCRS), interval);
|
|
57178
|
+
for (var y = 0; y < ys.length - 1; y++) {
|
|
57179
|
+
for (var x = 0; x < xs.length - 1; x++) {
|
|
57180
|
+
addTopologyMeshCell(context, xs[x], ys[y], xs[x + 1], ys[y + 1], 0);
|
|
57181
|
+
}
|
|
57182
|
+
}
|
|
57183
|
+
return mesh;
|
|
57184
|
+
}
|
|
57185
|
+
|
|
57186
|
+
function addTopologyMeshCell(context, x0, y0, x1, y1, depth) {
|
|
57187
|
+
var classification = classifyTopologyCell(context, x0, y0, x1, y1);
|
|
57188
|
+
var width = x1 - x0;
|
|
57189
|
+
var height = y1 - y0;
|
|
57190
|
+
var splitX = width > context.minCellSize && depth < context.maxDepth;
|
|
57191
|
+
var splitY = height > context.minCellSize && depth < context.maxDepth;
|
|
57192
|
+
if (classification.mixed && (splitX || splitY)) {
|
|
57193
|
+
subdivideTopologyMeshCell(context, x0, y0, x1, y1, depth, splitX, splitY);
|
|
57194
|
+
return;
|
|
57195
|
+
}
|
|
57196
|
+
if (classification.region == null || classification.mixed) {
|
|
57197
|
+
context.mesh.subdivisionSkippedCellCount++;
|
|
57198
|
+
return;
|
|
57199
|
+
}
|
|
57200
|
+
appendTopologyMeshCell(context, x0, y0, x1, y1, classification.region);
|
|
57201
|
+
}
|
|
57202
|
+
|
|
57203
|
+
function subdivideTopologyMeshCell(context, x0, y0, x1, y1, depth, splitX, splitY) {
|
|
57204
|
+
var xm = splitX ? (x0 + x1) / 2 : x1;
|
|
57205
|
+
var ym = splitY ? (y0 + y1) / 2 : y1;
|
|
57206
|
+
addTopologyMeshCell(context, x0, y0, xm, ym, depth + 1);
|
|
57207
|
+
if (splitX) addTopologyMeshCell(context, xm, y0, x1, ym, depth + 1);
|
|
57208
|
+
if (splitY) addTopologyMeshCell(context, x0, ym, xm, y1, depth + 1);
|
|
57209
|
+
if (splitX && splitY) addTopologyMeshCell(context, xm, ym, x1, y1, depth + 1);
|
|
57210
|
+
}
|
|
57211
|
+
|
|
57212
|
+
function classifyTopologyCell(context, x0, y0, x1, y1) {
|
|
57213
|
+
var cx = (x0 + x1) / 2;
|
|
57214
|
+
var cy = (y0 + y1) / 2;
|
|
57215
|
+
var region = getTopologyRegionAtPixel(context, cx, cy);
|
|
57216
|
+
var mixed = false;
|
|
57217
|
+
for (var iy = 0; iy <= TOPOLOGY_SAMPLE_STEPS && !mixed; iy++) {
|
|
57218
|
+
for (var ix = 0; ix <= TOPOLOGY_SAMPLE_STEPS; ix++) {
|
|
57219
|
+
var px = x0 + (x1 - x0) * ix / TOPOLOGY_SAMPLE_STEPS;
|
|
57220
|
+
var py = y0 + (y1 - y0) * iy / TOPOLOGY_SAMPLE_STEPS;
|
|
57221
|
+
px += (cx - px) * TOPOLOGY_VERTEX_INSET;
|
|
57222
|
+
py += (cy - py) * TOPOLOGY_VERTEX_INSET;
|
|
57223
|
+
if (getTopologyRegionAtPixel(context, px, py) !== region) {
|
|
57224
|
+
mixed = true;
|
|
57225
|
+
break;
|
|
57226
|
+
}
|
|
57227
|
+
}
|
|
57228
|
+
}
|
|
57229
|
+
return {region: region, mixed: mixed};
|
|
57230
|
+
}
|
|
57231
|
+
|
|
57232
|
+
function getTopologyRegionAtPixel(context, px, py) {
|
|
57233
|
+
var xy = rasterPixelToMapXY(context.grid, px, py);
|
|
57234
|
+
var lonlat = context.toGeographic(xy[0], xy[1]);
|
|
57235
|
+
if (!lonlat) return null;
|
|
57236
|
+
return context.findRegion(lonlat[0], lonlat[1]);
|
|
57237
|
+
}
|
|
57238
|
+
|
|
57239
|
+
function appendTopologyMeshCell(context, x0, y0, x1, y1, region) {
|
|
57240
|
+
var cx = (x0 + x1) / 2;
|
|
57241
|
+
var cy = (y0 + y1) / 2;
|
|
57242
|
+
var v00 = projectTopologyMeshVertex(context, x0, y0, cx, cy);
|
|
57243
|
+
var v10 = projectTopologyMeshVertex(context, x1, y0, cx, cy);
|
|
57244
|
+
var v01 = projectTopologyMeshVertex(context, x0, y1, cx, cy);
|
|
57245
|
+
var v11 = projectTopologyMeshVertex(context, x1, y1, cx, cy);
|
|
57246
|
+
var cell = {
|
|
57247
|
+
v00: v00,
|
|
57248
|
+
v10: v10,
|
|
57249
|
+
v01: v01,
|
|
57250
|
+
v11: v11,
|
|
57251
|
+
region: region,
|
|
57252
|
+
valid: vertexIsValid(v00) && vertexIsValid(v10) &&
|
|
57253
|
+
vertexIsValid(v01) && vertexIsValid(v11)
|
|
57254
|
+
};
|
|
57255
|
+
context.mesh.vertices.push(v00, v10, v01, v11);
|
|
57256
|
+
context.mesh.cells.push(cell);
|
|
57257
|
+
}
|
|
57258
|
+
|
|
57259
|
+
function projectTopologyMeshVertex(context, px, py, cx, cy) {
|
|
57260
|
+
var insetX = px + (cx - px) * TOPOLOGY_VERTEX_INSET;
|
|
57261
|
+
var insetY = py + (cy - py) * TOPOLOGY_VERTEX_INSET;
|
|
57262
|
+
var xy = rasterPixelToMapXY(context.grid, insetX, insetY);
|
|
57263
|
+
var lonlat = context.toGeographic(xy[0], xy[1]);
|
|
57264
|
+
var p = lonlat && context.toDestination(lonlat[0], lonlat[1]);
|
|
57265
|
+
return {
|
|
57266
|
+
sx: px,
|
|
57267
|
+
sy: py,
|
|
57268
|
+
x: p && isFinite(p[0]) ? p[0] : NaN,
|
|
57269
|
+
y: p && isFinite(p[1]) ? p[1] : NaN
|
|
57270
|
+
};
|
|
57271
|
+
}
|
|
57272
|
+
|
|
57273
|
+
function classifyRasterMesh(mesh, opts) {
|
|
57274
|
+
if (mesh.topologyAware) {
|
|
57275
|
+
classifyTopologyMeshCells(mesh);
|
|
57276
|
+
} else {
|
|
57277
|
+
classifyProjectedMeshCells(mesh, opts);
|
|
57278
|
+
}
|
|
57279
|
+
}
|
|
57280
|
+
|
|
57281
|
+
function classifyTopologyMeshCells(mesh) {
|
|
57282
|
+
var filtered = 0;
|
|
57283
|
+
mesh.cells.forEach(function(cell) {
|
|
57284
|
+
cell.maxEdge = getCellMaxEdge(cell);
|
|
57285
|
+
if (!cell.valid) {
|
|
57286
|
+
cell.valid = false;
|
|
57287
|
+
filtered++;
|
|
57288
|
+
}
|
|
57289
|
+
});
|
|
57290
|
+
// Topology-aware cells never span projection branches. Do not apply the
|
|
57291
|
+
// regular mesh's median-edge outlier filter here: adaptive subdivision
|
|
57292
|
+
// creates many small boundary cells that would make valid interior cells
|
|
57293
|
+
// appear to be outliers.
|
|
57294
|
+
mesh.maxEdge = Infinity;
|
|
57295
|
+
mesh.skippedCellCount = mesh.subdivisionSkippedCellCount + filtered;
|
|
57296
|
+
}
|
|
57297
|
+
|
|
55281
57298
|
function classifyProjectedMeshCells(mesh, opts) {
|
|
55282
57299
|
var cols = mesh.xs.length;
|
|
55283
57300
|
var cells = [];
|
|
@@ -55461,17 +57478,41 @@ ${svg}
|
|
|
55461
57478
|
];
|
|
55462
57479
|
}
|
|
55463
57480
|
|
|
57481
|
+
function rasterMapXYToPixel(grid, x, y) {
|
|
57482
|
+
var t = grid.transform;
|
|
57483
|
+
if (t) {
|
|
57484
|
+
return [
|
|
57485
|
+
(x - t[2]) / t[0],
|
|
57486
|
+
(y - t[5]) / t[4]
|
|
57487
|
+
];
|
|
57488
|
+
}
|
|
57489
|
+
return [
|
|
57490
|
+
(x - grid.bbox[0]) / (grid.bbox[2] - grid.bbox[0]) * grid.width,
|
|
57491
|
+
(grid.bbox[3] - y) / (grid.bbox[3] - grid.bbox[1]) * grid.height
|
|
57492
|
+
];
|
|
57493
|
+
}
|
|
57494
|
+
|
|
55464
57495
|
function getProjectedMeshBBox(mesh) {
|
|
55465
57496
|
var xmin = Infinity, ymin = Infinity, xmax = -Infinity, ymax = -Infinity;
|
|
55466
|
-
mesh.
|
|
55467
|
-
|
|
55468
|
-
|
|
55469
|
-
if (p.x < xmin) xmin = p.x;
|
|
55470
|
-
if (p.x > xmax) xmax = p.x;
|
|
55471
|
-
if (p.y < ymin) ymin = p.y;
|
|
55472
|
-
if (p.y > ymax) ymax = p.y;
|
|
57497
|
+
if (mesh.projectedRegions) {
|
|
57498
|
+
mesh.projectedRegions.forEach(function(region) {
|
|
57499
|
+
region.boundary.forEach(expand);
|
|
55473
57500
|
});
|
|
55474
|
-
}
|
|
57501
|
+
} else {
|
|
57502
|
+
mesh.cells.forEach(function(cell) {
|
|
57503
|
+
if (!cell.valid) return;
|
|
57504
|
+
[cell.v00, cell.v10, cell.v01, cell.v11].forEach(expand);
|
|
57505
|
+
});
|
|
57506
|
+
}
|
|
57507
|
+
function expand(p) {
|
|
57508
|
+
if (!p) return;
|
|
57509
|
+
var x = Array.isArray(p) ? p[0] : p.x;
|
|
57510
|
+
var y = Array.isArray(p) ? p[1] : p.y;
|
|
57511
|
+
if (x < xmin) xmin = x;
|
|
57512
|
+
if (x > xmax) xmax = x;
|
|
57513
|
+
if (y < ymin) ymin = y;
|
|
57514
|
+
if (y > ymax) ymax = y;
|
|
57515
|
+
}
|
|
55475
57516
|
return xmin < Infinity && xmax > xmin && ymax > ymin ? [xmin, ymin, xmax, ymax] : null;
|
|
55476
57517
|
}
|
|
55477
57518
|
|
|
@@ -55564,14 +57605,151 @@ ${svg}
|
|
|
55564
57605
|
}
|
|
55565
57606
|
|
|
55566
57607
|
function rasterizeProjectedMesh(srcGrid, destGrid, mesh, sampleMethod) {
|
|
57608
|
+
var regionData = mesh.projectedRegions ?
|
|
57609
|
+
createProjectedRegionMask(
|
|
57610
|
+
destGrid, mesh.projectedRegions, mesh.fillRegionMask) :
|
|
57611
|
+
null;
|
|
57612
|
+
(mesh.triangles || []).forEach(function(triangle) {
|
|
57613
|
+
if (!triangle.valid) return;
|
|
57614
|
+
var regionValue = regionData && regionData.values.get(triangle.region);
|
|
57615
|
+
rasterizeProjectedTriangle(
|
|
57616
|
+
srcGrid, destGrid, triangle.a, triangle.b, triangle.c,
|
|
57617
|
+
sampleMethod, regionData && regionData.mask, regionValue,
|
|
57618
|
+
mesh.sourceWrapX
|
|
57619
|
+
);
|
|
57620
|
+
});
|
|
55567
57621
|
mesh.cells.forEach(function(cell) {
|
|
55568
57622
|
if (!cell.valid) return;
|
|
55569
|
-
|
|
55570
|
-
rasterizeProjectedTriangle(
|
|
57623
|
+
var regionValue = regionData && regionData.values.get(cell.region);
|
|
57624
|
+
rasterizeProjectedTriangle(
|
|
57625
|
+
srcGrid, destGrid, cell.v00, cell.v10, cell.v11,
|
|
57626
|
+
sampleMethod, regionData && regionData.mask, regionValue, false
|
|
57627
|
+
);
|
|
57628
|
+
rasterizeProjectedTriangle(
|
|
57629
|
+
srcGrid, destGrid, cell.v00, cell.v11, cell.v01,
|
|
57630
|
+
sampleMethod, regionData && regionData.mask, regionValue, false
|
|
57631
|
+
);
|
|
57632
|
+
});
|
|
57633
|
+
}
|
|
57634
|
+
|
|
57635
|
+
function fillIsolatedProjectedRasterHoles(grid) {
|
|
57636
|
+
var holes = [];
|
|
57637
|
+
var width = grid.width;
|
|
57638
|
+
var height = grid.height;
|
|
57639
|
+
var coverage = grid.coverage;
|
|
57640
|
+
for (var y = 1; y < height - 1; y++) {
|
|
57641
|
+
for (var x = 1; x < width - 1; x++) {
|
|
57642
|
+
var i = y * width + x;
|
|
57643
|
+
if (!coverage[i] &&
|
|
57644
|
+
coverage[i - 1] && coverage[i + 1] &&
|
|
57645
|
+
coverage[i - width] && coverage[i + width]) {
|
|
57646
|
+
holes.push(i);
|
|
57647
|
+
}
|
|
57648
|
+
}
|
|
57649
|
+
}
|
|
57650
|
+
holes.forEach(function(i) {
|
|
57651
|
+
var src = (i - 1) * grid.bands;
|
|
57652
|
+
var dest = i * grid.bands;
|
|
57653
|
+
for (var band = 0; band < grid.bands; band++) {
|
|
57654
|
+
grid.samples[dest + band] = grid.samples[src + band];
|
|
57655
|
+
}
|
|
57656
|
+
coverage[i] = 1;
|
|
55571
57657
|
});
|
|
55572
57658
|
}
|
|
55573
57659
|
|
|
55574
|
-
function
|
|
57660
|
+
function fillProjectedRasterCoverage(grid) {
|
|
57661
|
+
// Used only for layouts whose projected outline fills the output rectangle.
|
|
57662
|
+
var width = grid.width;
|
|
57663
|
+
var height = grid.height;
|
|
57664
|
+
var coverage = grid.coverage;
|
|
57665
|
+
for (var y = 0; y < height; y++) {
|
|
57666
|
+
var row = y * width;
|
|
57667
|
+
var source = -1;
|
|
57668
|
+
for (var x = 0; x < width; x++) {
|
|
57669
|
+
var i = row + x;
|
|
57670
|
+
if (coverage[i]) {
|
|
57671
|
+
source = i;
|
|
57672
|
+
} else if (source >= 0) {
|
|
57673
|
+
copyProjectedRasterPixel(grid, source, i);
|
|
57674
|
+
}
|
|
57675
|
+
}
|
|
57676
|
+
source = -1;
|
|
57677
|
+
for (x = width - 1; x >= 0; x--) {
|
|
57678
|
+
i = row + x;
|
|
57679
|
+
if (coverage[i]) {
|
|
57680
|
+
source = i;
|
|
57681
|
+
} else if (source >= 0) {
|
|
57682
|
+
copyProjectedRasterPixel(grid, source, i);
|
|
57683
|
+
}
|
|
57684
|
+
}
|
|
57685
|
+
}
|
|
57686
|
+
}
|
|
57687
|
+
|
|
57688
|
+
function copyProjectedRasterPixel(grid, sourceIndex, destIndex) {
|
|
57689
|
+
var source = sourceIndex * grid.bands;
|
|
57690
|
+
var dest = destIndex * grid.bands;
|
|
57691
|
+
for (var band = 0; band < grid.bands; band++) {
|
|
57692
|
+
grid.samples[dest + band] = grid.samples[source + band];
|
|
57693
|
+
}
|
|
57694
|
+
grid.coverage[destIndex] = 1;
|
|
57695
|
+
}
|
|
57696
|
+
|
|
57697
|
+
function createProjectedRegionMask(grid, regions, fill) {
|
|
57698
|
+
var mask = new Uint8Array(grid.width * grid.height);
|
|
57699
|
+
var values = new Map();
|
|
57700
|
+
regions.forEach(function(region, i) {
|
|
57701
|
+
var value = i + 1;
|
|
57702
|
+
values.set(region.id, value);
|
|
57703
|
+
rasterizeRegionMask(grid, mask, region.boundary, value);
|
|
57704
|
+
});
|
|
57705
|
+
if (fill) fillRegionMask(mask, grid.width, grid.height);
|
|
57706
|
+
return {mask: mask, values: values};
|
|
57707
|
+
}
|
|
57708
|
+
|
|
57709
|
+
function fillRegionMask(mask, width, height) {
|
|
57710
|
+
for (var y = 0; y < height; y++) {
|
|
57711
|
+
var row = y * width;
|
|
57712
|
+
var value = 0;
|
|
57713
|
+
for (var x = 0; x < width; x++) {
|
|
57714
|
+
if (mask[row + x]) value = mask[row + x];
|
|
57715
|
+
else if (value) mask[row + x] = value;
|
|
57716
|
+
}
|
|
57717
|
+
value = 0;
|
|
57718
|
+
for (x = width - 1; x >= 0; x--) {
|
|
57719
|
+
if (mask[row + x]) value = mask[row + x];
|
|
57720
|
+
else if (value) mask[row + x] = value;
|
|
57721
|
+
}
|
|
57722
|
+
}
|
|
57723
|
+
}
|
|
57724
|
+
|
|
57725
|
+
function rasterizeRegionMask(grid, mask, boundary, value) {
|
|
57726
|
+
var ring = boundary.map(function(p) {
|
|
57727
|
+
return mapXYToRasterPixel(grid, p[0], p[1]);
|
|
57728
|
+
});
|
|
57729
|
+
var ymin = Math.max(0, Math.floor(Math.min.apply(null, ring.map(function(p) { return p[1]; }))));
|
|
57730
|
+
var ymax = Math.min(grid.height - 1, Math.ceil(Math.max.apply(null, ring.map(function(p) { return p[1]; }))));
|
|
57731
|
+
var intersections = [];
|
|
57732
|
+
for (var y = ymin; y <= ymax; y++) {
|
|
57733
|
+
var py = y + 0.5;
|
|
57734
|
+
intersections.length = 0;
|
|
57735
|
+
for (var i = 1; i < ring.length; i++) {
|
|
57736
|
+
var a = ring[i - 1];
|
|
57737
|
+
var b = ring[i];
|
|
57738
|
+
if ((a[1] > py) == (b[1] > py)) continue;
|
|
57739
|
+
intersections.push(a[0] + (py - a[1]) * (b[0] - a[0]) / (b[1] - a[1]));
|
|
57740
|
+
}
|
|
57741
|
+
intersections.sort(function(a, b) { return a - b; });
|
|
57742
|
+
for (var j = 1; j < intersections.length; j += 2) {
|
|
57743
|
+
var x0 = Math.max(0, Math.ceil(intersections[j - 1] - 0.5));
|
|
57744
|
+
var x1 = Math.min(grid.width - 1, Math.floor(intersections[j] - 0.5));
|
|
57745
|
+
for (var x = x0; x <= x1; x++) {
|
|
57746
|
+
mask[y * grid.width + x] = value;
|
|
57747
|
+
}
|
|
57748
|
+
}
|
|
57749
|
+
}
|
|
57750
|
+
}
|
|
57751
|
+
|
|
57752
|
+
function rasterizeProjectedTriangle(srcGrid, destGrid, a, b, c, sampleMethod, regionMask, regionValue, sourceWrapX) {
|
|
55575
57753
|
var bbox, x0, x1, y0, y1, det, w1, w2, w3, sx, sy, ap, bp, cp;
|
|
55576
57754
|
if (!vertexIsValid(a) || !vertexIsValid(b) || !vertexIsValid(c)) return;
|
|
55577
57755
|
ap = vertexToDestPixel(destGrid, a);
|
|
@@ -55583,13 +57761,15 @@ ${svg}
|
|
|
55583
57761
|
x0 = bbox[0]; y0 = bbox[1]; x1 = bbox[2]; y1 = bbox[3];
|
|
55584
57762
|
for (var y = y0; y <= y1; y++) {
|
|
55585
57763
|
for (var x = x0; x <= x1; x++) {
|
|
57764
|
+
if (regionMask && regionMask[y * destGrid.width + x] != regionValue) continue;
|
|
55586
57765
|
w1 = edgeFunction(bp, cp, x + 0.5, y + 0.5) / det;
|
|
55587
57766
|
w2 = edgeFunction(cp, ap, x + 0.5, y + 0.5) / det;
|
|
55588
57767
|
w3 = 1 - w1 - w2;
|
|
55589
57768
|
if (w1 < -1e-9 || w2 < -1e-9 || w3 < -1e-9) continue;
|
|
55590
57769
|
sx = w1 * a.sx + w2 * b.sx + w3 * c.sx;
|
|
55591
57770
|
sy = w1 * a.sy + w2 * b.sy + w3 * c.sy;
|
|
55592
|
-
copyRasterSample(
|
|
57771
|
+
copyRasterSample(
|
|
57772
|
+
srcGrid, destGrid, sx, sy, x, y, sampleMethod, sourceWrapX);
|
|
55593
57773
|
}
|
|
55594
57774
|
}
|
|
55595
57775
|
}
|
|
@@ -55621,16 +57801,18 @@ ${svg}
|
|
|
55621
57801
|
];
|
|
55622
57802
|
}
|
|
55623
57803
|
|
|
55624
|
-
function copyRasterSample(srcGrid, destGrid, sx, sy, dx, dy, sampleMethod) {
|
|
57804
|
+
function copyRasterSample(srcGrid, destGrid, sx, sy, dx, dy, sampleMethod, wrapX) {
|
|
55625
57805
|
if (sampleMethod == 'bilinear') {
|
|
55626
|
-
copyBilinearRasterSample(srcGrid, destGrid, sx, sy, dx, dy);
|
|
57806
|
+
copyBilinearRasterSample(srcGrid, destGrid, sx, sy, dx, dy, wrapX);
|
|
55627
57807
|
} else {
|
|
55628
|
-
copyNearestRasterSample(srcGrid, destGrid, sx, sy, dx, dy);
|
|
57808
|
+
copyNearestRasterSample(srcGrid, destGrid, sx, sy, dx, dy, wrapX);
|
|
55629
57809
|
}
|
|
55630
57810
|
}
|
|
55631
57811
|
|
|
55632
|
-
function copyNearestRasterSample(srcGrid, destGrid, sx, sy, dx, dy) {
|
|
55633
|
-
var srcX =
|
|
57812
|
+
function copyNearestRasterSample(srcGrid, destGrid, sx, sy, dx, dy, wrapX) {
|
|
57813
|
+
var srcX = wrapX ?
|
|
57814
|
+
modulo(Math.floor(sx), srcGrid.width) :
|
|
57815
|
+
clamp$1(Math.floor(sx), 0, srcGrid.width - 1);
|
|
55634
57816
|
var srcY = clamp$1(Math.floor(sy), 0, srcGrid.height - 1);
|
|
55635
57817
|
var src = (srcY * srcGrid.width + srcX) * srcGrid.bands;
|
|
55636
57818
|
var dest = (dy * destGrid.width + dx) * destGrid.bands;
|
|
@@ -55642,10 +57824,14 @@ ${svg}
|
|
|
55642
57824
|
if (destGrid.coverage) destGrid.coverage[dy * destGrid.width + dx] = 1;
|
|
55643
57825
|
}
|
|
55644
57826
|
|
|
55645
|
-
function copyBilinearRasterSample(srcGrid, destGrid, sx, sy, dx, dy) {
|
|
55646
|
-
|
|
57827
|
+
function copyBilinearRasterSample(srcGrid, destGrid, sx, sy, dx, dy, wrapX) {
|
|
57828
|
+
if (wrapX) sx = modulo(sx, srcGrid.width);
|
|
57829
|
+
var srcX = wrapX ?
|
|
57830
|
+
modulo(Math.floor(sx - 0.5), srcGrid.width) :
|
|
57831
|
+
clamp$1(Math.floor(sx - 0.5), 0, srcGrid.width - 1);
|
|
55647
57832
|
var srcY = clamp$1(Math.floor(sy - 0.5), 0, srcGrid.height - 1);
|
|
55648
|
-
var srcX2 =
|
|
57833
|
+
var srcX2 = wrapX ? (srcX + 1) % srcGrid.width :
|
|
57834
|
+
clamp$1(srcX + 1, 0, srcGrid.width - 1);
|
|
55649
57835
|
var srcY2 = clamp$1(srcY + 1, 0, srcGrid.height - 1);
|
|
55650
57836
|
var tx = clamp$1(sx - 0.5 - srcX, 0, 1);
|
|
55651
57837
|
var ty = clamp$1(sy - 0.5 - srcY, 0, 1);
|
|
@@ -55757,9 +57943,14 @@ ${svg}
|
|
|
55757
57943
|
return val < min ? min : val > max ? max : val;
|
|
55758
57944
|
}
|
|
55759
57945
|
|
|
57946
|
+
function modulo(val, base) {
|
|
57947
|
+
return (val % base + base) % base;
|
|
57948
|
+
}
|
|
57949
|
+
|
|
55760
57950
|
var RasterReprojection = /*#__PURE__*/Object.freeze({
|
|
55761
57951
|
__proto__: null,
|
|
55762
57952
|
buildProjectedRasterMesh: buildProjectedRasterMesh,
|
|
57953
|
+
buildTopologyAwareProjectedRasterMesh: buildTopologyAwareProjectedRasterMesh,
|
|
55763
57954
|
getProjectedRasterGridBBox: getProjectedRasterGridBBox,
|
|
55764
57955
|
getProjectedRasterMeshBBox: getProjectedRasterMeshBBox,
|
|
55765
57956
|
projectRasterGridForward: projectRasterGridForward
|
|
@@ -55910,9 +58101,6 @@ ${svg}
|
|
|
55910
58101
|
if (isProjectedCRS(src) && !isInvertibleCRS(src)) {
|
|
55911
58102
|
stop$1('Unable to project from a coordinate system that has no inverse transform');
|
|
55912
58103
|
}
|
|
55913
|
-
if (isInterruptedProjection(dest) && dataset.layers.some(layerHasRaster)) {
|
|
55914
|
-
stop$1('Raster reprojection is not currently supported for interrupted projections');
|
|
55915
|
-
}
|
|
55916
58104
|
var proj = getProjTransform2(src, dest); // v2 returns null points instead of throwing an error
|
|
55917
58105
|
var badArcs = 0;
|
|
55918
58106
|
var badPoints = 0;
|
|
@@ -60312,7 +62500,7 @@ ${svg}
|
|
|
60312
62500
|
// Isometric ("Mercator-stretched") latitude in degrees-in; returns +/-Infinity at
|
|
60313
62501
|
// the poles.
|
|
60314
62502
|
function isometricLatitude(latDeg) {
|
|
60315
|
-
return Math.log(Math.tan(Math.PI / 4 + latDeg * D2R$
|
|
62503
|
+
return Math.log(Math.tan(Math.PI / 4 + latDeg * D2R$8 / 2));
|
|
60316
62504
|
}
|
|
60317
62505
|
|
|
60318
62506
|
// Rhumb-line (loxodrome) interpolation, fraction k of the way from A to B.
|
|
@@ -60337,9 +62525,9 @@ ${svg}
|
|
|
60337
62525
|
// Rhumb-line distance in meters, using the raw longitude delta (so a full-parallel
|
|
60338
62526
|
// sweep returns the parallel's length rather than 0).
|
|
60339
62527
|
function rhumbDistance(a, b) {
|
|
60340
|
-
var phi1 = a[1] * D2R$
|
|
62528
|
+
var phi1 = a[1] * D2R$8, phi2 = b[1] * D2R$8;
|
|
60341
62529
|
var dPhi = phi2 - phi1;
|
|
60342
|
-
var dLambda = (b[0] - a[0]) * D2R$
|
|
62530
|
+
var dLambda = (b[0] - a[0]) * D2R$8; // raw
|
|
60343
62531
|
var dPsi = Math.log(Math.tan(Math.PI / 4 + phi2 / 2) / Math.tan(Math.PI / 4 + phi1 / 2));
|
|
60344
62532
|
var q = Math.abs(dPsi) > 1e-12 ? dPhi / dPsi : Math.cos(phi1);
|
|
60345
62533
|
return Math.sqrt(dPhi * dPhi + q * q * dLambda * dLambda) * R$3;
|
|
@@ -67498,6 +69686,9 @@ ${svg}
|
|
|
67498
69686
|
var commands;
|
|
67499
69687
|
try {
|
|
67500
69688
|
commands = parseCommands(commandStr);
|
|
69689
|
+
if (opts && opts.validate_commands) {
|
|
69690
|
+
opts.validate_commands(commands);
|
|
69691
|
+
}
|
|
67501
69692
|
} catch(e) {
|
|
67502
69693
|
e.message = 'Error in command file ' + file + ': ' + e.message;
|
|
67503
69694
|
throw e;
|
|
@@ -67519,6 +69710,9 @@ ${svg}
|
|
|
67519
69710
|
}
|
|
67520
69711
|
if (c.name == 'run') {
|
|
67521
69712
|
c.options._run_depth = depth;
|
|
69713
|
+
if (opts && opts.validate_commands) {
|
|
69714
|
+
c.options.validate_commands = opts.validate_commands;
|
|
69715
|
+
}
|
|
67522
69716
|
}
|
|
67523
69717
|
});
|
|
67524
69718
|
|
|
@@ -67556,6 +69750,9 @@ ${svg}
|
|
|
67556
69750
|
ctx = getBaseContext();
|
|
67557
69751
|
// io proxy adds ability to add datasets dynamically in a required function
|
|
67558
69752
|
ctx.io = getIOProxy();
|
|
69753
|
+
if (opts.input) {
|
|
69754
|
+
Object.assign(ctx.io._cache, opts.input);
|
|
69755
|
+
}
|
|
67559
69756
|
tmp = await evalTemplateExpression(opts.expression, targets, ctx);
|
|
67560
69757
|
if (tmp && !utils.isString(tmp)) {
|
|
67561
69758
|
stop$1('Expected a string containing mapshaper commands; received:', tmp);
|
|
@@ -67564,6 +69761,9 @@ ${svg}
|
|
|
67564
69761
|
// truncate message (command might include a large GeoJSON string in an -i command)
|
|
67565
69762
|
message(`command: [${truncateString(tmp, 150)}]`);
|
|
67566
69763
|
commands = parseCommands(tmp);
|
|
69764
|
+
if (opts.validate_commands) {
|
|
69765
|
+
opts.validate_commands(commands);
|
|
69766
|
+
}
|
|
67567
69767
|
|
|
67568
69768
|
// TODO: remove duplication with mapshaper-run-commands.mjs
|
|
67569
69769
|
var outputArr = opts && opts.output || null;
|
|
@@ -67578,6 +69778,9 @@ ${svg}
|
|
|
67578
69778
|
cmd.name == 'info' && cmd.options.save_to)) {
|
|
67579
69779
|
cmd.options.output = outputArr;
|
|
67580
69780
|
}
|
|
69781
|
+
if (cmd.name == 'run' && opts.validate_commands) {
|
|
69782
|
+
cmd.options.validate_commands = opts.validate_commands;
|
|
69783
|
+
}
|
|
67581
69784
|
});
|
|
67582
69785
|
|
|
67583
69786
|
await utils.promisify(runParsedCommands)(commands, job);
|
|
@@ -70114,7 +72317,7 @@ ${svg}
|
|
|
70114
72317
|
if (Object.prototype.hasOwnProperty.call(command, '_sourceOverride')) {
|
|
70115
72318
|
source = command._sourceOverride;
|
|
70116
72319
|
} else if (opts.source) {
|
|
70117
|
-
source =
|
|
72320
|
+
source = await findCommandSourceAsync(convertSourceName(opts.source, targets), job.catalog, opts);
|
|
70118
72321
|
}
|
|
70119
72322
|
|
|
70120
72323
|
// identify command target/input (for postprocessing)
|
|
@@ -70520,7 +72723,7 @@ ${svg}
|
|
|
70520
72723
|
var disposableSourceTargetIndex = -1;
|
|
70521
72724
|
|
|
70522
72725
|
if (command.options.source && !sourceNameIsInterpolated(command.options.source)) {
|
|
70523
|
-
source = resolveSourceForTargets(command, job, targets);
|
|
72726
|
+
source = await resolveSourceForTargets(command, job, targets);
|
|
70524
72727
|
items = moveSourceTargetLast(items, source);
|
|
70525
72728
|
disposableSourceTargetIndex = findLastDisposableSourceTarget(
|
|
70526
72729
|
items,
|
|
@@ -70555,10 +72758,10 @@ ${svg}
|
|
|
70555
72758
|
return job;
|
|
70556
72759
|
}
|
|
70557
72760
|
|
|
70558
|
-
function resolveSourceForTargets(command, job, targets) {
|
|
72761
|
+
async function resolveSourceForTargets(command, job, targets) {
|
|
70559
72762
|
job.startCommand(command);
|
|
70560
72763
|
try {
|
|
70561
|
-
return
|
|
72764
|
+
return await findCommandSourceAsync(
|
|
70562
72765
|
convertSourceName(command.options.source, targets),
|
|
70563
72766
|
job.catalog,
|
|
70564
72767
|
command.options
|
|
@@ -70660,7 +72863,7 @@ ${svg}
|
|
|
70660
72863
|
return name == 'rectangle' || name == 'rectangles' || name == 'filter' && opts.cleanup;
|
|
70661
72864
|
}
|
|
70662
72865
|
|
|
70663
|
-
var version = "0.7.
|
|
72866
|
+
var version = "0.7.47";
|
|
70664
72867
|
|
|
70665
72868
|
// Parse command line args into commands and run them
|
|
70666
72869
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|
|
@@ -70690,7 +72893,6 @@ ${svg}
|
|
|
70690
72893
|
if (err) {
|
|
70691
72894
|
return callback(err);
|
|
70692
72895
|
}
|
|
70693
|
-
if (opts.legacy) return callback(null, toLegacyOutputFormat(outputArr));
|
|
70694
72896
|
return callback(null, toOutputFormat(outputArr));
|
|
70695
72897
|
});
|
|
70696
72898
|
if (opts.promise) return opts.promise;
|
|
@@ -70732,9 +72934,6 @@ ${svg}
|
|
|
70732
72934
|
opts.callback = arg1;
|
|
70733
72935
|
} else if (utils.isFunction(arg2)) {
|
|
70734
72936
|
opts.callback = arg2;
|
|
70735
|
-
// identify legacy input format (used by some tests)
|
|
70736
|
-
opts.legacy = arg1 && guessInputContentType(arg1) != null;
|
|
70737
|
-
opts.input = arg1;
|
|
70738
72937
|
} else {
|
|
70739
72938
|
// if no callback, create a promise and a callback for resolving the promise
|
|
70740
72939
|
opts.promise = new Promise(function(resolve, reject) {
|
|
@@ -70744,7 +72943,7 @@ ${svg}
|
|
|
70744
72943
|
};
|
|
70745
72944
|
});
|
|
70746
72945
|
}
|
|
70747
|
-
if (
|
|
72946
|
+
if (utils.isObject(arg1)) {
|
|
70748
72947
|
if (arg1.xl) {
|
|
70749
72948
|
// options for runCommandsXL()
|
|
70750
72949
|
opts.options = arg1;
|
|
@@ -70777,12 +72976,6 @@ ${svg}
|
|
|
70777
72976
|
return callback(e);
|
|
70778
72977
|
}
|
|
70779
72978
|
|
|
70780
|
-
if (opts.legacy) {
|
|
70781
|
-
message("Warning: deprecated input format");
|
|
70782
|
-
commands = convertLegacyCommands(commands, inputObj);
|
|
70783
|
-
inputObj = null;
|
|
70784
|
-
}
|
|
70785
|
-
|
|
70786
72979
|
if (commands.length === 0) {
|
|
70787
72980
|
return callback(new UserError("No commands to run"));
|
|
70788
72981
|
}
|
|
@@ -70819,13 +73012,22 @@ ${svg}
|
|
|
70819
73012
|
// (e.g. `mapshaper *.shp batch-mode -o out.json` writing all inputs to the
|
|
70820
73013
|
// same target on disk).
|
|
70821
73014
|
var sharedOutputs = [];
|
|
70822
|
-
|
|
73015
|
+
runBatches().then(function(job) {
|
|
73016
|
+
done(null, job);
|
|
73017
|
+
}, done);
|
|
70823
73018
|
|
|
70824
|
-
function
|
|
70825
|
-
|
|
70826
|
-
|
|
70827
|
-
|
|
70828
|
-
|
|
73019
|
+
async function runBatches() {
|
|
73020
|
+
var job;
|
|
73021
|
+
for (var batch of batches) {
|
|
73022
|
+
try {
|
|
73023
|
+
job = await runParsedCommands(batch, new Job(null, {output_files: sharedOutputs}));
|
|
73024
|
+
} catch (e) {
|
|
73025
|
+
var fatalError = handleNonFatalError(e);
|
|
73026
|
+
if (fatalError) throw fatalError;
|
|
73027
|
+
job = undefined;
|
|
73028
|
+
}
|
|
73029
|
+
}
|
|
73030
|
+
return job;
|
|
70829
73031
|
}
|
|
70830
73032
|
|
|
70831
73033
|
function done(err, job) {
|
|
@@ -70839,33 +73041,6 @@ ${svg}
|
|
|
70839
73041
|
}
|
|
70840
73042
|
|
|
70841
73043
|
|
|
70842
|
-
function toLegacyOutputFormat(arr) {
|
|
70843
|
-
if (arr.length > 1) {
|
|
70844
|
-
// Return an array if multiple files are output
|
|
70845
|
-
return utils.pluck(arr, 'content');
|
|
70846
|
-
}
|
|
70847
|
-
if (arr.length == 1) {
|
|
70848
|
-
// Return content if a single file is output
|
|
70849
|
-
return arr[0].content;
|
|
70850
|
-
}
|
|
70851
|
-
return null;
|
|
70852
|
-
}
|
|
70853
|
-
|
|
70854
|
-
function convertLegacyCommands(arr, inputObj) {
|
|
70855
|
-
var i = utils.find(arr, function(cmd) {return cmd.name == 'i';});
|
|
70856
|
-
var o = utils.find(arr, function(cmd) {return cmd.name == 'o';});
|
|
70857
|
-
if (!i) {
|
|
70858
|
-
i = {name: 'i', options: {}};
|
|
70859
|
-
arr.unshift(i);
|
|
70860
|
-
}
|
|
70861
|
-
i.options.files = ['__input__'];
|
|
70862
|
-
i.options.input = {__input__: inputObj};
|
|
70863
|
-
if (!o) {
|
|
70864
|
-
arr.push({name: 'o', options: {}});
|
|
70865
|
-
}
|
|
70866
|
-
return arr;
|
|
70867
|
-
}
|
|
70868
|
-
|
|
70869
73044
|
// TODO: rewrite tests and remove this function
|
|
70870
73045
|
function testCommands(argv, done) {
|
|
70871
73046
|
_runCommands(argv, {}, function(err, job) {
|
|
@@ -70883,9 +73058,20 @@ ${svg}
|
|
|
70883
73058
|
// Execute a sequence of parsed commands
|
|
70884
73059
|
// @commands Array of parsed commands
|
|
70885
73060
|
// @job: Job object containing previously imported data
|
|
70886
|
-
// @done: function([error], [job])
|
|
73061
|
+
// @done: optional function([error], [job]); returns a Promise if omitted
|
|
70887
73062
|
//
|
|
70888
73063
|
function runParsedCommands(commands, job, done) {
|
|
73064
|
+
var promise = runParsedCommandsAsync(commands, job);
|
|
73065
|
+
if (done) {
|
|
73066
|
+
promise.then(function(job) {
|
|
73067
|
+
done(null, job);
|
|
73068
|
+
}, done);
|
|
73069
|
+
return;
|
|
73070
|
+
}
|
|
73071
|
+
return promise;
|
|
73072
|
+
}
|
|
73073
|
+
|
|
73074
|
+
async function runParsedCommandsAsync(commands, job) {
|
|
70889
73075
|
if (!job) job = new Job();
|
|
70890
73076
|
commands = readAndRemoveSettings(job, commands);
|
|
70891
73077
|
if (!runningInBrowser()) {
|
|
@@ -70893,26 +73079,16 @@ ${svg}
|
|
|
70893
73079
|
}
|
|
70894
73080
|
commands = runAndRemoveInfoCommands(commands);
|
|
70895
73081
|
if (commands.length === 0) {
|
|
70896
|
-
return
|
|
73082
|
+
return;
|
|
70897
73083
|
}
|
|
70898
73084
|
// we're no longer using the same Job for all batches -- no reset needed
|
|
70899
73085
|
// // resetting closes any unterminated -if blocks from a previous command sequence
|
|
70900
73086
|
// resetControlFlow(job);
|
|
70901
|
-
|
|
70902
|
-
|
|
70903
|
-
|
|
70904
|
-
var resolved;
|
|
70905
|
-
try {
|
|
70906
|
-
resolved = maybeInterpolateCommand(cmd, job);
|
|
70907
|
-
} catch(e) {
|
|
70908
|
-
return next(e);
|
|
70909
|
-
}
|
|
70910
|
-
runCommand(resolved, job).then(function(result) {
|
|
70911
|
-
next(null, result);
|
|
70912
|
-
}).catch(function(e) {
|
|
70913
|
-
next(e);
|
|
70914
|
-
});
|
|
73087
|
+
for (var command of commands) {
|
|
73088
|
+
var resolved = maybeInterpolateCommand(command, job);
|
|
73089
|
+
job = await runCommand(resolved, job);
|
|
70915
73090
|
}
|
|
73091
|
+
return job;
|
|
70916
73092
|
}
|
|
70917
73093
|
|
|
70918
73094
|
// Late-binding interpolation: just before each command runs, replace any
|
|
@@ -72526,6 +74702,7 @@ ${svg}
|
|
|
72526
74702
|
CustomProjections,
|
|
72527
74703
|
Dymaxion,
|
|
72528
74704
|
ButterflyProjections,
|
|
74705
|
+
Narukawa2022,
|
|
72529
74706
|
DataAggregation,
|
|
72530
74707
|
DatasetUtils,
|
|
72531
74708
|
DataUtils,
|