mapshaper 0.7.46 → 0.7.48
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 +2466 -230
- package/package.json +1 -1
- package/www/mapshaper.js +2466 -230
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$5(val, min, max) {
|
|
82
82
|
return val < min ? min : (val > max ? max : val);
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -721,7 +721,7 @@
|
|
|
721
721
|
function findValueByRank(arr, rank) {
|
|
722
722
|
if (!arr.length || rank < 1 || rank > arr.length) error$1("[findValueByRank()] invalid input");
|
|
723
723
|
|
|
724
|
-
rank = clamp$
|
|
724
|
+
rank = clamp$5(rank | 0, 1, arr.length);
|
|
725
725
|
var k = rank - 1, // conv. rank to array index
|
|
726
726
|
n = arr.length,
|
|
727
727
|
l = 0,
|
|
@@ -1095,7 +1095,7 @@
|
|
|
1095
1095
|
// self-import and the resulting Rollup circular-dependency warning.
|
|
1096
1096
|
var utils = {
|
|
1097
1097
|
addThousandsSep, addslashes, arrayToIndex,
|
|
1098
|
-
clamp: clamp$
|
|
1098
|
+
clamp: clamp$5, cleanNumericString, contains, copyElements, countValues, createBuffer,
|
|
1099
1099
|
defaults, difference,
|
|
1100
1100
|
endsWith, every, expandoBuffer, extend: extend$1, extendBuffer,
|
|
1101
1101
|
find: find$1, findMedian, findQuantile, findRankByValue, findStringPrefix,
|
|
@@ -2053,12 +2053,12 @@
|
|
|
2053
2053
|
// TODO: remove this constant, use actual data from dataset CRS,
|
|
2054
2054
|
// also consider using ellipsoidal formulas where greater accuracy might be important.
|
|
2055
2055
|
var R$3 = WGS84.SEMIMAJOR_AXIS;
|
|
2056
|
-
var D2R$
|
|
2057
|
-
var R2D$
|
|
2056
|
+
var D2R$8 = Math.PI / 180;
|
|
2057
|
+
var R2D$7 = 180 / Math.PI;
|
|
2058
2058
|
|
|
2059
2059
|
// Equirectangular projection
|
|
2060
2060
|
function degreesToMeters(deg) {
|
|
2061
|
-
return deg * D2R$
|
|
2061
|
+
return deg * D2R$8 * R$3;
|
|
2062
2062
|
}
|
|
2063
2063
|
|
|
2064
2064
|
function distance3D(ax, ay, az, bx, by, bz) {
|
|
@@ -2205,16 +2205,16 @@
|
|
|
2205
2205
|
|
|
2206
2206
|
function xyzToLngLat(x, y, z, p) {
|
|
2207
2207
|
var d = distance3D(0, 0, 0, x, y, z); // normalize
|
|
2208
|
-
var lat = Math.asin(z / d) / D2R$
|
|
2209
|
-
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;
|
|
2210
2210
|
p[0] = lng;
|
|
2211
2211
|
p[1] = lat;
|
|
2212
2212
|
}
|
|
2213
2213
|
|
|
2214
2214
|
function lngLatToXYZ(lng, lat, p) {
|
|
2215
2215
|
var cosLat;
|
|
2216
|
-
lng *= D2R$
|
|
2217
|
-
lat *= D2R$
|
|
2216
|
+
lng *= D2R$8;
|
|
2217
|
+
lat *= D2R$8;
|
|
2218
2218
|
cosLat = Math.cos(lat);
|
|
2219
2219
|
p[0] = Math.cos(lng) * cosLat * R$3;
|
|
2220
2220
|
p[1] = Math.sin(lng) * cosLat * R$3;
|
|
@@ -2334,9 +2334,9 @@
|
|
|
2334
2334
|
|
|
2335
2335
|
var Geom = /*#__PURE__*/Object.freeze({
|
|
2336
2336
|
__proto__: null,
|
|
2337
|
-
D2R: D2R$
|
|
2337
|
+
D2R: D2R$8,
|
|
2338
2338
|
R: R$3,
|
|
2339
|
-
R2D: R2D$
|
|
2339
|
+
R2D: R2D$7,
|
|
2340
2340
|
bearing: bearing,
|
|
2341
2341
|
bearing2D: bearing2D,
|
|
2342
2342
|
containsBounds: containsBounds,
|
|
@@ -6264,9 +6264,9 @@
|
|
|
6264
6264
|
* ISC License: https://github.com/d3/d3-geo-polygon/blob/main/LICENSE
|
|
6265
6265
|
*/
|
|
6266
6266
|
|
|
6267
|
-
var D2R$
|
|
6268
|
-
var R2D$
|
|
6269
|
-
var EPS$
|
|
6267
|
+
var D2R$7 = Math.PI / 180;
|
|
6268
|
+
var R2D$6 = 180 / Math.PI;
|
|
6269
|
+
var EPS$3 = 1e-12;
|
|
6270
6270
|
|
|
6271
6271
|
// Build a forward-only spherical polyhedral projection.
|
|
6272
6272
|
//
|
|
@@ -6304,10 +6304,10 @@
|
|
|
6304
6304
|
throw new Error('Invalid polyhedral face tree');
|
|
6305
6305
|
}
|
|
6306
6306
|
var childEdge = shared.map(function(p) {
|
|
6307
|
-
return face.project(p[0] * D2R$
|
|
6307
|
+
return face.project(p[0] * D2R$7, p[1] * D2R$7);
|
|
6308
6308
|
});
|
|
6309
6309
|
var parentEdge = shared.map(function(p) {
|
|
6310
|
-
return parent.project(p[0] * D2R$
|
|
6310
|
+
return parent.project(p[0] * D2R$7, p[1] * D2R$7);
|
|
6311
6311
|
});
|
|
6312
6312
|
face.transform = multiplyMatrices(
|
|
6313
6313
|
parent.transform,
|
|
@@ -6318,12 +6318,12 @@
|
|
|
6318
6318
|
|
|
6319
6319
|
var rootEdge = findLongestEdge(faces[0].coords);
|
|
6320
6320
|
var rootPlanarEdge = rootEdge.map(function(p) {
|
|
6321
|
-
return faces[0].project(p[0] * D2R$
|
|
6321
|
+
return faces[0].project(p[0] * D2R$7, p[1] * D2R$7);
|
|
6322
6322
|
});
|
|
6323
6323
|
var sphericalEdgeLength = angularDistance(rootEdge[0], rootEdge[1]);
|
|
6324
6324
|
var planarEdgeLength = distance2D(rootPlanarEdge[0], rootPlanarEdge[1]);
|
|
6325
6325
|
var scale = sphericalEdgeLength / planarEdgeLength;
|
|
6326
|
-
var planarAngle = (config.angle || 0) * D2R$
|
|
6326
|
+
var planarAngle = (config.angle || 0) * D2R$7;
|
|
6327
6327
|
var edgeIndex = indexEdges(faces, attachedPairs);
|
|
6328
6328
|
var outline = buildOutline(faces, attachedPairs).map(function(ring) {
|
|
6329
6329
|
return ring.map(transformOutputPoint);
|
|
@@ -6344,6 +6344,8 @@
|
|
|
6344
6344
|
faces: faces,
|
|
6345
6345
|
outline: outline,
|
|
6346
6346
|
forward: forward,
|
|
6347
|
+
forwardFace: forwardFace,
|
|
6348
|
+
invertFace: invertFace,
|
|
6347
6349
|
findFace: findFace,
|
|
6348
6350
|
findTransitionRegion: findTransitionRegion,
|
|
6349
6351
|
getTopology: getTopology
|
|
@@ -6353,27 +6355,74 @@
|
|
|
6353
6355
|
var rotated = rotateRadians(
|
|
6354
6356
|
lam,
|
|
6355
6357
|
phi,
|
|
6356
|
-
config.rotation[0] * D2R$
|
|
6357
|
-
config.rotation[1] * D2R$
|
|
6358
|
-
config.rotation[2] * D2R$
|
|
6358
|
+
config.rotation[0] * D2R$7,
|
|
6359
|
+
config.rotation[1] * D2R$7,
|
|
6360
|
+
config.rotation[2] * D2R$7
|
|
6359
6361
|
);
|
|
6360
6362
|
var face = findFaceRotated(rotated[0], rotated[1]);
|
|
6361
6363
|
if (!face) return null;
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
+
return projectFacePoint(face, rotated[0], rotated[1]);
|
|
6365
|
+
}
|
|
6366
|
+
|
|
6367
|
+
function forwardFace(lam, phi, faceId) {
|
|
6368
|
+
var rotated = rotateRadians(
|
|
6369
|
+
lam,
|
|
6370
|
+
phi,
|
|
6371
|
+
config.rotation[0] * D2R$7,
|
|
6372
|
+
config.rotation[1] * D2R$7,
|
|
6373
|
+
config.rotation[2] * D2R$7
|
|
6374
|
+
);
|
|
6375
|
+
var face = faces[faceId];
|
|
6376
|
+
return face ? projectFacePoint(face, rotated[0], rotated[1]) : null;
|
|
6377
|
+
}
|
|
6378
|
+
|
|
6379
|
+
function projectFacePoint(face, lam, phi) {
|
|
6380
|
+
var p = face.project(lam, phi);
|
|
6381
|
+
p = applyMatrix$1(face.transform, p);
|
|
6364
6382
|
p = transformOutputPoint(p);
|
|
6365
6383
|
p[0] -= centerX;
|
|
6366
6384
|
p[1] -= centerY;
|
|
6367
6385
|
return p;
|
|
6368
6386
|
}
|
|
6369
6387
|
|
|
6388
|
+
function invertFace(x, y, faceId) {
|
|
6389
|
+
var face = faces[faceId];
|
|
6390
|
+
var p, rotated;
|
|
6391
|
+
if (!face || !face.project.invert) return null;
|
|
6392
|
+
p = inverseTransformOutputPoint([x + centerX, y + centerY]);
|
|
6393
|
+
p = applyMatrix$1(invertMatrix$1(face.transform), p);
|
|
6394
|
+
rotated = face.project.invert(p[0], p[1]);
|
|
6395
|
+
if (!rotated) return null;
|
|
6396
|
+
return rotateRadians(
|
|
6397
|
+
rotated[0],
|
|
6398
|
+
rotated[1],
|
|
6399
|
+
config.rotation[0] * D2R$7,
|
|
6400
|
+
config.rotation[1] * D2R$7,
|
|
6401
|
+
config.rotation[2] * D2R$7,
|
|
6402
|
+
true
|
|
6403
|
+
);
|
|
6404
|
+
}
|
|
6405
|
+
|
|
6406
|
+
function inverseTransformOutputPoint(p) {
|
|
6407
|
+
var x = p[0];
|
|
6408
|
+
var y = p[1];
|
|
6409
|
+
if (planarAngle) {
|
|
6410
|
+
var cos = Math.cos(planarAngle);
|
|
6411
|
+
var sin = Math.sin(planarAngle);
|
|
6412
|
+
var x2 = x * cos + y * sin;
|
|
6413
|
+
y = -x * sin + y * cos;
|
|
6414
|
+
x = x2;
|
|
6415
|
+
}
|
|
6416
|
+
return [x / scale, -y / scale];
|
|
6417
|
+
}
|
|
6418
|
+
|
|
6370
6419
|
function findFace(lam, phi) {
|
|
6371
6420
|
var rotated = rotateRadians(
|
|
6372
6421
|
lam,
|
|
6373
6422
|
phi,
|
|
6374
|
-
config.rotation[0] * D2R$
|
|
6375
|
-
config.rotation[1] * D2R$
|
|
6376
|
-
config.rotation[2] * D2R$
|
|
6423
|
+
config.rotation[0] * D2R$7,
|
|
6424
|
+
config.rotation[1] * D2R$7,
|
|
6425
|
+
config.rotation[2] * D2R$7
|
|
6377
6426
|
);
|
|
6378
6427
|
var face = findFaceRotated(rotated[0], rotated[1]);
|
|
6379
6428
|
return face ? face.id : -1;
|
|
@@ -6383,9 +6432,9 @@
|
|
|
6383
6432
|
var rotated = rotateRadians(
|
|
6384
6433
|
lam,
|
|
6385
6434
|
phi,
|
|
6386
|
-
config.rotation[0] * D2R$
|
|
6387
|
-
config.rotation[1] * D2R$
|
|
6388
|
-
config.rotation[2] * D2R$
|
|
6435
|
+
config.rotation[0] * D2R$7,
|
|
6436
|
+
config.rotation[1] * D2R$7,
|
|
6437
|
+
config.rotation[2] * D2R$7
|
|
6389
6438
|
);
|
|
6390
6439
|
var face = findFaceRotated(rotated[0], rotated[1]);
|
|
6391
6440
|
var region;
|
|
@@ -6427,16 +6476,16 @@
|
|
|
6427
6476
|
var seams = edgeIndex.map(function(edge) {
|
|
6428
6477
|
var endpoints = edge.points.map(function(p) {
|
|
6429
6478
|
var q = rotateRadians(
|
|
6430
|
-
p[0] * D2R$
|
|
6431
|
-
p[1] * D2R$
|
|
6432
|
-
config.rotation[0] * D2R$
|
|
6433
|
-
config.rotation[1] * D2R$
|
|
6434
|
-
config.rotation[2] * D2R$
|
|
6479
|
+
p[0] * D2R$7,
|
|
6480
|
+
p[1] * D2R$7,
|
|
6481
|
+
config.rotation[0] * D2R$7,
|
|
6482
|
+
config.rotation[1] * D2R$7,
|
|
6483
|
+
config.rotation[2] * D2R$7,
|
|
6435
6484
|
true
|
|
6436
6485
|
);
|
|
6437
|
-
return [normalizeLongitude$
|
|
6486
|
+
return [normalizeLongitude$3(q[0] * R2D$6 + lon0), q[1] * R2D$6];
|
|
6438
6487
|
});
|
|
6439
|
-
var paths = splitPathAtAntimeridian$
|
|
6488
|
+
var paths = splitPathAtAntimeridian$3(
|
|
6440
6489
|
interpolateGreatCircle(endpoints[0], endpoints[1], 0.05)
|
|
6441
6490
|
);
|
|
6442
6491
|
paths.forEach(function(path) {
|
|
@@ -6457,16 +6506,23 @@
|
|
|
6457
6506
|
});
|
|
6458
6507
|
return {
|
|
6459
6508
|
regions: faces.map(function(face) {
|
|
6460
|
-
return {
|
|
6509
|
+
return {
|
|
6510
|
+
id: face.id,
|
|
6511
|
+
projected_boundary: getProjectedFaceBoundary(face)
|
|
6512
|
+
};
|
|
6461
6513
|
}),
|
|
6462
6514
|
seams: seams,
|
|
6463
6515
|
findRegion: function(lon, lat) {
|
|
6464
|
-
var lam = normalizeLongitude$
|
|
6465
|
-
return findFace(lam, lat * D2R$
|
|
6516
|
+
var lam = normalizeLongitude$3(lon - lon0) * D2R$7;
|
|
6517
|
+
return findFace(lam, lat * D2R$7);
|
|
6466
6518
|
},
|
|
6467
6519
|
findTransitionRegion: function(lon, lat) {
|
|
6468
|
-
var lam = normalizeLongitude$
|
|
6469
|
-
return findTransitionRegion(lam, lat * D2R$
|
|
6520
|
+
var lam = normalizeLongitude$3(lon - lon0) * D2R$7;
|
|
6521
|
+
return findTransitionRegion(lam, lat * D2R$7);
|
|
6522
|
+
},
|
|
6523
|
+
projectRegion: function(lon, lat, regionId) {
|
|
6524
|
+
var lam = normalizeLongitude$3(lon - lon0) * D2R$7;
|
|
6525
|
+
return forwardFace(lam, lat * D2R$7, regionId);
|
|
6470
6526
|
},
|
|
6471
6527
|
regionsAreAttached: function(a, b) {
|
|
6472
6528
|
return regionPairs.get(pairKey(a, b)) === true;
|
|
@@ -6478,15 +6534,29 @@
|
|
|
6478
6534
|
})
|
|
6479
6535
|
};
|
|
6480
6536
|
}
|
|
6537
|
+
|
|
6538
|
+
function getProjectedFaceBoundary(face) {
|
|
6539
|
+
var ring = [];
|
|
6540
|
+
for (var i = 0; i < face.coords.length; i++) {
|
|
6541
|
+
var a = face.coords[i];
|
|
6542
|
+
var b = face.coords[(i + 1) % face.coords.length];
|
|
6543
|
+
var edge = interpolateGreatCircle(a, b, 0.5);
|
|
6544
|
+
for (var j = 0; j < edge.length - 1; j++) {
|
|
6545
|
+
ring.push(projectFacePoint(face, edge[j][0] * D2R$7, edge[j][1] * D2R$7));
|
|
6546
|
+
}
|
|
6547
|
+
}
|
|
6548
|
+
ring.push(ring[0].concat());
|
|
6549
|
+
return ring;
|
|
6550
|
+
}
|
|
6481
6551
|
}
|
|
6482
6552
|
|
|
6483
6553
|
function rotateSphericalRadians(lam, phi, rotation, invert) {
|
|
6484
6554
|
return rotateRadians(
|
|
6485
6555
|
lam,
|
|
6486
6556
|
phi,
|
|
6487
|
-
(rotation[0] || 0) * D2R$
|
|
6488
|
-
(rotation[1] || 0) * D2R$
|
|
6489
|
-
(rotation[2] || 0) * D2R$
|
|
6557
|
+
(rotation[0] || 0) * D2R$7,
|
|
6558
|
+
(rotation[1] || 0) * D2R$7,
|
|
6559
|
+
(rotation[2] || 0) * D2R$7,
|
|
6490
6560
|
invert
|
|
6491
6561
|
);
|
|
6492
6562
|
}
|
|
@@ -6523,7 +6593,7 @@
|
|
|
6523
6593
|
function faceContainsVector(face, p) {
|
|
6524
6594
|
for (var i = 0; i < face.edges.length; i++) {
|
|
6525
6595
|
var edge = face.edges[i];
|
|
6526
|
-
if (dot$2(edge.normal, p) * edge.sign < -EPS$
|
|
6596
|
+
if (dot$2(edge.normal, p) * edge.sign < -EPS$3) return false;
|
|
6527
6597
|
}
|
|
6528
6598
|
return true;
|
|
6529
6599
|
}
|
|
@@ -6559,8 +6629,8 @@
|
|
|
6559
6629
|
var adjacent = findAdjacentFace(faces, face.id, a, b);
|
|
6560
6630
|
if (adjacent >= 0 && attachedPairs.has(pairKey(face.id, adjacent))) continue;
|
|
6561
6631
|
edges.push([
|
|
6562
|
-
applyMatrix(face.transform, face.project(a[0] * D2R$
|
|
6563
|
-
applyMatrix(face.transform, face.project(b[0] * D2R$
|
|
6632
|
+
applyMatrix$1(face.transform, face.project(a[0] * D2R$7, a[1] * D2R$7)),
|
|
6633
|
+
applyMatrix$1(face.transform, face.project(b[0] * D2R$7, b[1] * D2R$7))
|
|
6564
6634
|
]);
|
|
6565
6635
|
}
|
|
6566
6636
|
});
|
|
@@ -6677,13 +6747,25 @@
|
|
|
6677
6747
|
];
|
|
6678
6748
|
}
|
|
6679
6749
|
|
|
6680
|
-
function applyMatrix(m, p) {
|
|
6750
|
+
function applyMatrix$1(m, p) {
|
|
6681
6751
|
return [
|
|
6682
6752
|
m[0] * p[0] + m[1] * p[1] + m[2],
|
|
6683
6753
|
m[3] * p[0] + m[4] * p[1] + m[5]
|
|
6684
6754
|
];
|
|
6685
6755
|
}
|
|
6686
6756
|
|
|
6757
|
+
function invertMatrix$1(m) {
|
|
6758
|
+
var det = m[0] * m[4] - m[1] * m[3];
|
|
6759
|
+
return [
|
|
6760
|
+
m[4] / det,
|
|
6761
|
+
-m[1] / det,
|
|
6762
|
+
(m[1] * m[5] - m[4] * m[2]) / det,
|
|
6763
|
+
-m[3] / det,
|
|
6764
|
+
m[0] / det,
|
|
6765
|
+
(m[3] * m[2] - m[0] * m[5]) / det
|
|
6766
|
+
];
|
|
6767
|
+
}
|
|
6768
|
+
|
|
6687
6769
|
function rotateRadians(lam, phi, deltaLam, deltaPhi, deltaGamma, invert) {
|
|
6688
6770
|
if (invert) {
|
|
6689
6771
|
var inv = rotatePhiGamma$1(lam, phi, deltaPhi, deltaGamma, true);
|
|
@@ -6709,28 +6791,28 @@
|
|
|
6709
6791
|
return [
|
|
6710
6792
|
Math.atan2(y * cosDeltaGamma + z * sinDeltaGamma,
|
|
6711
6793
|
x * cosDeltaPhi + k * sinDeltaPhi),
|
|
6712
|
-
Math.asin(clamp$
|
|
6794
|
+
Math.asin(clamp$4(k * cosDeltaPhi - x * sinDeltaPhi, -1, 1))
|
|
6713
6795
|
];
|
|
6714
6796
|
}
|
|
6715
6797
|
k = z * cosDeltaPhi + x * sinDeltaPhi;
|
|
6716
6798
|
return [
|
|
6717
6799
|
Math.atan2(y * cosDeltaGamma - k * sinDeltaGamma,
|
|
6718
6800
|
x * cosDeltaPhi - z * sinDeltaPhi),
|
|
6719
|
-
Math.asin(clamp$
|
|
6801
|
+
Math.asin(clamp$4(k * cosDeltaGamma + y * sinDeltaGamma, -1, 1))
|
|
6720
6802
|
];
|
|
6721
6803
|
}
|
|
6722
6804
|
|
|
6723
6805
|
function interpolateGreatCircle(a, b, interval) {
|
|
6724
6806
|
var av = degreesToVector$2(a[0], a[1]);
|
|
6725
6807
|
var bv = degreesToVector$2(b[0], b[1]);
|
|
6726
|
-
var angle = Math.acos(clamp$
|
|
6727
|
-
var n = Math.max(1, Math.ceil(angle * R2D$
|
|
6808
|
+
var angle = Math.acos(clamp$4(dot$2(av, bv), -1, 1));
|
|
6809
|
+
var n = Math.max(1, Math.ceil(angle * R2D$6 / interval));
|
|
6728
6810
|
var sinAngle = Math.sin(angle);
|
|
6729
6811
|
var points = [];
|
|
6730
6812
|
for (var i = 0; i <= n; i++) {
|
|
6731
6813
|
var t = i / n;
|
|
6732
6814
|
var p;
|
|
6733
|
-
if (sinAngle < EPS$
|
|
6815
|
+
if (sinAngle < EPS$3) {
|
|
6734
6816
|
p = av;
|
|
6735
6817
|
} else {
|
|
6736
6818
|
var ka = Math.sin((1 - t) * angle) / sinAngle;
|
|
@@ -6746,7 +6828,7 @@
|
|
|
6746
6828
|
return points;
|
|
6747
6829
|
}
|
|
6748
6830
|
|
|
6749
|
-
function splitPathAtAntimeridian$
|
|
6831
|
+
function splitPathAtAntimeridian$3(path) {
|
|
6750
6832
|
var paths = [];
|
|
6751
6833
|
var part = [path[0]];
|
|
6752
6834
|
for (var i = 1; i < path.length; i++) {
|
|
@@ -6782,12 +6864,12 @@
|
|
|
6782
6864
|
}
|
|
6783
6865
|
|
|
6784
6866
|
function angularDistance(a, b) {
|
|
6785
|
-
return Math.acos(clamp$
|
|
6867
|
+
return Math.acos(clamp$4(dot$2(degreesToVector$2(a[0], a[1]),
|
|
6786
6868
|
degreesToVector$2(b[0], b[1])), -1, 1));
|
|
6787
6869
|
}
|
|
6788
6870
|
|
|
6789
6871
|
function degreesToVector$2(lon, lat) {
|
|
6790
|
-
return radiansToVector$1(lon * D2R$
|
|
6872
|
+
return radiansToVector$1(lon * D2R$7, lat * D2R$7);
|
|
6791
6873
|
}
|
|
6792
6874
|
|
|
6793
6875
|
function radiansToVector$1(lam, phi) {
|
|
@@ -6797,8 +6879,8 @@
|
|
|
6797
6879
|
|
|
6798
6880
|
function vectorToDegrees$2(p) {
|
|
6799
6881
|
return [
|
|
6800
|
-
Math.atan2(p[1], p[0]) * R2D$
|
|
6801
|
-
Math.asin(clamp$
|
|
6882
|
+
Math.atan2(p[1], p[0]) * R2D$6,
|
|
6883
|
+
Math.asin(clamp$4(p[2], -1, 1)) * R2D$6
|
|
6802
6884
|
];
|
|
6803
6885
|
}
|
|
6804
6886
|
|
|
@@ -6826,7 +6908,7 @@
|
|
|
6826
6908
|
}
|
|
6827
6909
|
|
|
6828
6910
|
function sameSphericalPoint(a, b) {
|
|
6829
|
-
return Math.abs(a[0] - b[0]) < EPS$
|
|
6911
|
+
return Math.abs(a[0] - b[0]) < EPS$3 && Math.abs(a[1] - b[1]) < EPS$3;
|
|
6830
6912
|
}
|
|
6831
6913
|
|
|
6832
6914
|
function pointsAlmostEqual(a, b) {
|
|
@@ -6853,13 +6935,13 @@
|
|
|
6853
6935
|
return lam;
|
|
6854
6936
|
}
|
|
6855
6937
|
|
|
6856
|
-
function normalizeLongitude$
|
|
6938
|
+
function normalizeLongitude$3(lon) {
|
|
6857
6939
|
while (lon > 180) lon -= 360;
|
|
6858
6940
|
while (lon < -180) lon += 360;
|
|
6859
6941
|
return lon;
|
|
6860
6942
|
}
|
|
6861
6943
|
|
|
6862
|
-
function clamp$
|
|
6944
|
+
function clamp$4(val, min, max) {
|
|
6863
6945
|
return Math.max(min, Math.min(max, val));
|
|
6864
6946
|
}
|
|
6865
6947
|
|
|
@@ -6875,9 +6957,9 @@
|
|
|
6875
6957
|
*/
|
|
6876
6958
|
|
|
6877
6959
|
|
|
6878
|
-
var D2R$
|
|
6879
|
-
var R2D$
|
|
6880
|
-
var SQRT3$
|
|
6960
|
+
var D2R$6 = Math.PI / 180;
|
|
6961
|
+
var R2D$5 = 180 / Math.PI;
|
|
6962
|
+
var SQRT3$2 = Math.sqrt(3);
|
|
6881
6963
|
var GRAY_Z = Math.sqrt(5 + 2 * Math.sqrt(5)) / Math.sqrt(15);
|
|
6882
6964
|
var GRAY_EL = Math.sqrt(8) / Math.sqrt(5 + Math.sqrt(5));
|
|
6883
6965
|
var GRAY_DVE = Math.sqrt(3 + Math.sqrt(5)) / Math.sqrt(5 + Math.sqrt(5));
|
|
@@ -6889,7 +6971,7 @@
|
|
|
6889
6971
|
6, 8, 10, 17, 21,
|
|
6890
6972
|
16, 15, 19, 19
|
|
6891
6973
|
];
|
|
6892
|
-
var engines$
|
|
6974
|
+
var engines$3 = {};
|
|
6893
6975
|
|
|
6894
6976
|
function registerDymaxionProjections(mproj) {
|
|
6895
6977
|
// Some unit tests import source modules directly in an ESM context where
|
|
@@ -6908,9 +6990,9 @@
|
|
|
6908
6990
|
|
|
6909
6991
|
function getDymaxionEngine(method) {
|
|
6910
6992
|
method = method || 'fuller';
|
|
6911
|
-
if (!engines$
|
|
6993
|
+
if (!engines$3[method]) {
|
|
6912
6994
|
var data = createAiroceanFaces();
|
|
6913
|
-
engines$
|
|
6995
|
+
engines$3[method] = createPolyhedralProjection({
|
|
6914
6996
|
faces: data.faces,
|
|
6915
6997
|
faceSites: data.sites,
|
|
6916
6998
|
parents: PARENTS,
|
|
@@ -6921,7 +7003,7 @@
|
|
|
6921
7003
|
createGrayFullerFaceProjector
|
|
6922
7004
|
});
|
|
6923
7005
|
}
|
|
6924
|
-
return engines$
|
|
7006
|
+
return engines$3[method];
|
|
6925
7007
|
}
|
|
6926
7008
|
|
|
6927
7009
|
function initDymaxion(P, method) {
|
|
@@ -6937,12 +7019,12 @@
|
|
|
6937
7019
|
xy.y = p[1];
|
|
6938
7020
|
}
|
|
6939
7021
|
};
|
|
6940
|
-
P.__projection_topology = engine.getTopology(P.lam0 * R2D$
|
|
7022
|
+
P.__projection_topology = engine.getTopology(P.lam0 * R2D$5);
|
|
6941
7023
|
P.__projected_outline = engine.outline;
|
|
6942
7024
|
}
|
|
6943
7025
|
|
|
6944
7026
|
function createAiroceanFaces() {
|
|
6945
|
-
var theta = Math.atan(0.5) * R2D$
|
|
7027
|
+
var theta = Math.atan(0.5) * R2D$5;
|
|
6946
7028
|
var vertices = [[0, 90], [0, -90]];
|
|
6947
7029
|
var faces;
|
|
6948
7030
|
var sites;
|
|
@@ -7039,10 +7121,10 @@
|
|
|
7039
7121
|
var s = GRAY_Z / (cosPhi * Math.cos(lam));
|
|
7040
7122
|
var x = cosPhi * Math.sin(lam) * s;
|
|
7041
7123
|
var y = Math.sin(phi) * s;
|
|
7042
|
-
var a1p = Math.atan2(2 * y / SQRT3$
|
|
7043
|
-
var a2p = Math.atan2(x - y / SQRT3$
|
|
7044
|
-
var a3p = Math.atan2(GRAY_EL / 3 - x - y / SQRT3$
|
|
7045
|
-
return [SQRT3$
|
|
7124
|
+
var a1p = Math.atan2(2 * y / SQRT3$2 + GRAY_EL / 3 - GRAY_EL / 2, GRAY_DVE);
|
|
7125
|
+
var a2p = Math.atan2(x - y / SQRT3$2 + GRAY_EL / 3 - GRAY_EL / 2, GRAY_DVE);
|
|
7126
|
+
var a3p = Math.atan2(GRAY_EL / 3 - x - y / SQRT3$2 - GRAY_EL / 2, GRAY_DVE);
|
|
7127
|
+
return [SQRT3$2 * (a2p - a3p), 2 * a1p - a2p - a3p];
|
|
7046
7128
|
}
|
|
7047
7129
|
|
|
7048
7130
|
function getSphericalCentroid(coords) {
|
|
@@ -7067,16 +7149,16 @@
|
|
|
7067
7149
|
}
|
|
7068
7150
|
|
|
7069
7151
|
function degreesToVector$1(p) {
|
|
7070
|
-
var lam = p[0] * D2R$
|
|
7071
|
-
var phi = p[1] * D2R$
|
|
7152
|
+
var lam = p[0] * D2R$6;
|
|
7153
|
+
var phi = p[1] * D2R$6;
|
|
7072
7154
|
var cosPhi = Math.cos(phi);
|
|
7073
7155
|
return [Math.cos(lam) * cosPhi, Math.sin(lam) * cosPhi, Math.sin(phi)];
|
|
7074
7156
|
}
|
|
7075
7157
|
|
|
7076
7158
|
function vectorToDegrees$1(p) {
|
|
7077
7159
|
return [
|
|
7078
|
-
Math.atan2(p[1], p[0]) * R2D$
|
|
7079
|
-
Math.asin(Math.max(-1, Math.min(1, p[2]))) * R2D$
|
|
7160
|
+
Math.atan2(p[1], p[0]) * R2D$5,
|
|
7161
|
+
Math.asin(Math.max(-1, Math.min(1, p[2]))) * R2D$5
|
|
7080
7162
|
];
|
|
7081
7163
|
}
|
|
7082
7164
|
|
|
@@ -7124,8 +7206,8 @@
|
|
|
7124
7206
|
* ISC License: https://github.com/d3/d3-geo-polygon/blob/main/LICENSE
|
|
7125
7207
|
*/
|
|
7126
7208
|
|
|
7127
|
-
var D2R$
|
|
7128
|
-
var R2D$
|
|
7209
|
+
var D2R$5 = Math.PI / 180;
|
|
7210
|
+
var R2D$4 = 180 / Math.PI;
|
|
7129
7211
|
|
|
7130
7212
|
function createCahillKeyesRaw(mg) {
|
|
7131
7213
|
return createCahillKeyesTransform(mg, false);
|
|
@@ -7137,12 +7219,12 @@
|
|
|
7137
7219
|
|
|
7138
7220
|
return function(lambda, phi) {
|
|
7139
7221
|
if (faceOnly) {
|
|
7140
|
-
var lon = lambda * R2D$
|
|
7222
|
+
var lon = lambda * R2D$4;
|
|
7141
7223
|
var side = lon < 0 ? -1 : lon > 0 ? 1 : 0;
|
|
7142
|
-
var local = mp2xy(Math.abs(lon), Math.abs(phi * R2D$
|
|
7224
|
+
var local = mp2xy(Math.abs(lon), Math.abs(phi * R2D$4));
|
|
7143
7225
|
return [local[0], side * local[1]];
|
|
7144
7226
|
}
|
|
7145
|
-
var res = ll2mp(lambda * R2D$
|
|
7227
|
+
var res = ll2mp(lambda * R2D$4, phi * R2D$4);
|
|
7146
7228
|
var xy = mp2xy(res[0], res[1]);
|
|
7147
7229
|
var p = [xy[0], res[2] * xy[1]];
|
|
7148
7230
|
return mj2g(p, res[3]);
|
|
@@ -7160,7 +7242,7 @@
|
|
|
7160
7242
|
CK.cos60 = 0.5;
|
|
7161
7243
|
CK.pointM = [0, 0];
|
|
7162
7244
|
CK.pointG = [CK.lengthMG, 0];
|
|
7163
|
-
pointN = [CK.lengthMG, CK.lengthMG * Math.tan(30 * D2R$
|
|
7245
|
+
pointN = [CK.lengthMG, CK.lengthMG * Math.tan(30 * D2R$5)];
|
|
7164
7246
|
CK.pointA = [CK.lengthMA, 0];
|
|
7165
7247
|
CK.pointB = lineIntersection(CK.pointM, 30, CK.pointA, 45);
|
|
7166
7248
|
CK.lengthAG = distance(CK.pointA, CK.pointG);
|
|
@@ -7171,8 +7253,8 @@
|
|
|
7171
7253
|
CK.pointD = interpolate(lengthMB, lengthMN, pointN, CK.pointM);
|
|
7172
7254
|
CK.pointF = [CK.lengthMG, lengthNG - lengthMB];
|
|
7173
7255
|
CK.pointE = [
|
|
7174
|
-
pointN[0] - CK.lengthMA * Math.sin(30 * D2R$
|
|
7175
|
-
pointN[1] - CK.lengthMA * Math.cos(30 * D2R$
|
|
7256
|
+
pointN[0] - CK.lengthMA * Math.sin(30 * D2R$5),
|
|
7257
|
+
pointN[1] - CK.lengthMA * Math.cos(30 * D2R$5)
|
|
7176
7258
|
];
|
|
7177
7259
|
CK.lengthGF = distance(CK.pointG, CK.pointF);
|
|
7178
7260
|
CK.lengthBD = distance(CK.pointB, CK.pointD);
|
|
@@ -7182,8 +7264,8 @@
|
|
|
7182
7264
|
CK.lengthAP73 = CK.lengthMG - CK.lengthMA -
|
|
7183
7265
|
CK.lengthParallel0to73At0 * 73;
|
|
7184
7266
|
pointU = [
|
|
7185
|
-
CK.pointA[0] + CK.lengthAP73 * Math.cos(30 * D2R$
|
|
7186
|
-
CK.pointA[1] + CK.lengthAP73 * Math.sin(30 * D2R$
|
|
7267
|
+
CK.pointA[0] + CK.lengthAP73 * Math.cos(30 * D2R$5),
|
|
7268
|
+
CK.pointA[1] + CK.lengthAP73 * Math.sin(30 * D2R$5)
|
|
7187
7269
|
];
|
|
7188
7270
|
CK.pointT = lineIntersection(pointU, -60, CK.pointB, 30);
|
|
7189
7271
|
|
|
@@ -7424,8 +7506,8 @@
|
|
|
7424
7506
|
|
|
7425
7507
|
function radialPoint(origin, length, angle) {
|
|
7426
7508
|
return [
|
|
7427
|
-
origin[0] + length * Math.cos(angle * D2R$
|
|
7428
|
-
origin[1] + length * Math.sin(angle * D2R$
|
|
7509
|
+
origin[0] + length * Math.cos(angle * D2R$5),
|
|
7510
|
+
origin[1] + length * Math.sin(angle * D2R$5)
|
|
7429
7511
|
];
|
|
7430
7512
|
}
|
|
7431
7513
|
|
|
@@ -7442,8 +7524,8 @@
|
|
|
7442
7524
|
-xy[0] * CK.sin60 - xy[1] * CK.cos60
|
|
7443
7525
|
];
|
|
7444
7526
|
}
|
|
7445
|
-
var cos = Math.cos(angle * D2R$
|
|
7446
|
-
var sin = Math.sin(angle * D2R$
|
|
7527
|
+
var cos = Math.cos(angle * D2R$5);
|
|
7528
|
+
var sin = Math.sin(angle * D2R$5);
|
|
7447
7529
|
return [xy[0] * cos - xy[1] * sin, xy[0] * sin + xy[1] * cos];
|
|
7448
7530
|
}
|
|
7449
7531
|
}
|
|
@@ -7464,8 +7546,8 @@
|
|
|
7464
7546
|
}
|
|
7465
7547
|
|
|
7466
7548
|
function lineIntersection(p1, slope1, p2, slope2) {
|
|
7467
|
-
var m1 = Math.tan(slope1 * D2R$
|
|
7468
|
-
var m2 = Math.tan(slope2 * D2R$
|
|
7549
|
+
var m1 = Math.tan(slope1 * D2R$5);
|
|
7550
|
+
var m2 = Math.tan(slope2 * D2R$5);
|
|
7469
7551
|
var x = (m1 * p1[0] - m2 * p2[0] - p1[1] + p2[1]) / (m1 - m2);
|
|
7470
7552
|
return [x, m1 * (x - p1[0]) + p1[1]];
|
|
7471
7553
|
}
|
|
@@ -7493,8 +7575,8 @@
|
|
|
7493
7575
|
return n > 0 ? Math.floor(n) : Math.ceil(n);
|
|
7494
7576
|
}
|
|
7495
7577
|
|
|
7496
|
-
var D2R$
|
|
7497
|
-
var EPS$
|
|
7578
|
+
var D2R$4 = Math.PI / 180;
|
|
7579
|
+
var EPS$2 = 1e-12;
|
|
7498
7580
|
|
|
7499
7581
|
// Create a smooth facet projection from any radial azimuthal projection.
|
|
7500
7582
|
// The azimuthal coordinates are warped back to the gnomonic polygon along
|
|
@@ -7504,7 +7586,7 @@
|
|
|
7504
7586
|
var center = options.planarCenter || getSphericalCenter(coords);
|
|
7505
7587
|
var gnomonic = createGnomonicProjector(center);
|
|
7506
7588
|
var planar = coords.map(function(p) {
|
|
7507
|
-
return gnomonic(p[0] * D2R$
|
|
7589
|
+
return gnomonic(p[0] * D2R$4, p[1] * D2R$4);
|
|
7508
7590
|
});
|
|
7509
7591
|
var edges = createNormalizedEdges(planar);
|
|
7510
7592
|
var radial = createRadialFunction(
|
|
@@ -7523,7 +7605,7 @@
|
|
|
7523
7605
|
function project(lam, phi) {
|
|
7524
7606
|
var p = gnomonic(lam, phi);
|
|
7525
7607
|
var r = Math.hypot(p[0], p[1]);
|
|
7526
|
-
if (r < EPS$
|
|
7608
|
+
if (r < EPS$2) return [0, 0];
|
|
7527
7609
|
var c = Math.atan(r);
|
|
7528
7610
|
var azimuthalRadius = radial(c) * radialScale;
|
|
7529
7611
|
var boundaryWeight = getBoundaryWeight(p, edges, boundaryStrength);
|
|
@@ -7613,8 +7695,8 @@
|
|
|
7613
7695
|
|
|
7614
7696
|
function getSphericalCenter(coords) {
|
|
7615
7697
|
var sum = coords.reduce(function(memo, p) {
|
|
7616
|
-
var lam = p[0] * D2R$
|
|
7617
|
-
var phi = p[1] * D2R$
|
|
7698
|
+
var lam = p[0] * D2R$4;
|
|
7699
|
+
var phi = p[1] * D2R$4;
|
|
7618
7700
|
var cosPhi = Math.cos(phi);
|
|
7619
7701
|
memo[0] += Math.cos(lam) * cosPhi;
|
|
7620
7702
|
memo[1] += Math.sin(lam) * cosPhi;
|
|
@@ -7622,8 +7704,8 @@
|
|
|
7622
7704
|
return memo;
|
|
7623
7705
|
}, [0, 0, 0]);
|
|
7624
7706
|
return [
|
|
7625
|
-
Math.atan2(sum[1], sum[0]) / D2R$
|
|
7626
|
-
Math.atan2(sum[2], Math.hypot(sum[0], sum[1])) / D2R$
|
|
7707
|
+
Math.atan2(sum[1], sum[0]) / D2R$4,
|
|
7708
|
+
Math.atan2(sum[2], Math.hypot(sum[0], sum[1])) / D2R$4
|
|
7627
7709
|
];
|
|
7628
7710
|
}
|
|
7629
7711
|
|
|
@@ -7638,8 +7720,8 @@
|
|
|
7638
7720
|
*/
|
|
7639
7721
|
|
|
7640
7722
|
|
|
7641
|
-
var D2R$
|
|
7642
|
-
var R2D$
|
|
7723
|
+
var D2R$3 = Math.PI / 180;
|
|
7724
|
+
var R2D$3 = 180 / Math.PI;
|
|
7643
7725
|
var RADIAL_BOUNDARY_STRENGTH = 1;
|
|
7644
7726
|
var OCTAHEDRON = createOctahedron();
|
|
7645
7727
|
var BUTTERFLY_PARENTS = [-1, 0, 0, 1, 0, 1, 4, 5];
|
|
@@ -7648,7 +7730,7 @@
|
|
|
7648
7730
|
butterfly2: -20,
|
|
7649
7731
|
cahill_keyes: -20
|
|
7650
7732
|
};
|
|
7651
|
-
var engines$
|
|
7733
|
+
var engines$2 = {};
|
|
7652
7734
|
|
|
7653
7735
|
function registerButterflyProjections(mproj) {
|
|
7654
7736
|
if (!mproj) return;
|
|
@@ -7666,22 +7748,22 @@
|
|
|
7666
7748
|
|
|
7667
7749
|
function getButterflyEngine(method) {
|
|
7668
7750
|
var key = method == 'butterfly2' ? 'butterfly' : method;
|
|
7669
|
-
if (!engines$
|
|
7751
|
+
if (!engines$2[key]) {
|
|
7670
7752
|
if (key == 'cahill_keyes') {
|
|
7671
|
-
engines$
|
|
7753
|
+
engines$2[key] = createCahillKeyesEngine();
|
|
7672
7754
|
} else if (key == 'butterfly') {
|
|
7673
|
-
engines$
|
|
7755
|
+
engines$2[key] = createButterflyEngine();
|
|
7674
7756
|
} else {
|
|
7675
7757
|
throw new Error('Unknown butterfly projection: ' + method);
|
|
7676
7758
|
}
|
|
7677
7759
|
}
|
|
7678
|
-
return engines$
|
|
7760
|
+
return engines$2[key];
|
|
7679
7761
|
}
|
|
7680
7762
|
|
|
7681
7763
|
function initButterfly(P, method) {
|
|
7682
7764
|
var engine = getButterflyEngine(method);
|
|
7683
7765
|
if (!P.params.lon_0) {
|
|
7684
|
-
P.lam0 = DEFAULT_LON0[method] * D2R$
|
|
7766
|
+
P.lam0 = DEFAULT_LON0[method] * D2R$3;
|
|
7685
7767
|
}
|
|
7686
7768
|
P.es = 0;
|
|
7687
7769
|
P.inv = null;
|
|
@@ -7694,7 +7776,7 @@
|
|
|
7694
7776
|
xy.y = p[1];
|
|
7695
7777
|
}
|
|
7696
7778
|
};
|
|
7697
|
-
P.__projection_topology = engine.getTopology(P.lam0 * R2D$
|
|
7779
|
+
P.__projection_topology = engine.getTopology(P.lam0 * R2D$3);
|
|
7698
7780
|
if (engine.removeOutlineExtremeConnectors) {
|
|
7699
7781
|
P.__remove_outline_extreme_connectors = true;
|
|
7700
7782
|
}
|
|
@@ -7708,8 +7790,8 @@
|
|
|
7708
7790
|
// Reuse the Cahill-Keyes polar incisions and 12-zone octant transform,
|
|
7709
7791
|
// then unfold the faces with the butterfly attachment tree.
|
|
7710
7792
|
var data = createTruncatedOctahedronFaces(
|
|
7711
|
-
Math.cos(17 * D2R$
|
|
7712
|
-
Math.sin(17 * D2R$
|
|
7793
|
+
Math.cos(17 * D2R$3),
|
|
7794
|
+
Math.sin(17 * D2R$3),
|
|
7713
7795
|
BUTTERFLY_PARENTS
|
|
7714
7796
|
);
|
|
7715
7797
|
var faceRaw = createCahillKeyesFaceRaw(10000);
|
|
@@ -7722,7 +7804,7 @@
|
|
|
7722
7804
|
findFace: createTruncatedFaceFinder(data.cornerNormals),
|
|
7723
7805
|
faceProjector: function(face) {
|
|
7724
7806
|
var baseId = face.id < 8 ? face.id : data.parents[face.id];
|
|
7725
|
-
var center = faceCenters[baseId] * D2R$
|
|
7807
|
+
var center = faceCenters[baseId] * D2R$3;
|
|
7726
7808
|
var raw = function(lam, phi) {
|
|
7727
7809
|
return faceRaw(normalizeRadians$1(lam - center), phi);
|
|
7728
7810
|
};
|
|
@@ -7737,7 +7819,7 @@
|
|
|
7737
7819
|
// Remove the global placement and scale of a raw facet while preserving its
|
|
7738
7820
|
// internal shape. The polyhedral engine then controls how facets unfold.
|
|
7739
7821
|
var points = coords.map(function(p) {
|
|
7740
|
-
return raw(p[0] * D2R$
|
|
7822
|
+
return raw(p[0] * D2R$3, p[1] * D2R$3);
|
|
7741
7823
|
});
|
|
7742
7824
|
var edge = 0;
|
|
7743
7825
|
var maxLengthSq = -1;
|
|
@@ -7826,8 +7908,8 @@
|
|
|
7826
7908
|
|
|
7827
7909
|
function createCahillKeyesEngine() {
|
|
7828
7910
|
var data = createTruncatedOctahedronFaces(
|
|
7829
|
-
Math.cos(17 * D2R$
|
|
7830
|
-
Math.sin(17 * D2R$
|
|
7911
|
+
Math.cos(17 * D2R$3),
|
|
7912
|
+
Math.sin(17 * D2R$3),
|
|
7831
7913
|
[-1, 3, 0, 2, 0, 1, 4, 5]
|
|
7832
7914
|
);
|
|
7833
7915
|
var raw = createCahillKeyesRaw(10000);
|
|
@@ -7972,7 +8054,7 @@
|
|
|
7972
8054
|
}
|
|
7973
8055
|
|
|
7974
8056
|
function planarAngle(p, project) {
|
|
7975
|
-
var q = project(p[0] * D2R$
|
|
8057
|
+
var q = project(p[0] * D2R$3, p[1] * D2R$3);
|
|
7976
8058
|
return Math.atan2(q[1], q[0]);
|
|
7977
8059
|
}
|
|
7978
8060
|
|
|
@@ -8006,16 +8088,16 @@
|
|
|
8006
8088
|
}
|
|
8007
8089
|
|
|
8008
8090
|
function degreesToVector(p) {
|
|
8009
|
-
var lam = p[0] * D2R$
|
|
8010
|
-
var phi = p[1] * D2R$
|
|
8091
|
+
var lam = p[0] * D2R$3;
|
|
8092
|
+
var phi = p[1] * D2R$3;
|
|
8011
8093
|
var cosPhi = Math.cos(phi);
|
|
8012
8094
|
return [Math.cos(lam) * cosPhi, Math.sin(lam) * cosPhi, Math.sin(phi)];
|
|
8013
8095
|
}
|
|
8014
8096
|
|
|
8015
8097
|
function vectorToDegrees(p) {
|
|
8016
8098
|
return [
|
|
8017
|
-
Math.atan2(p[1], p[0]) * R2D$
|
|
8018
|
-
Math.asin(Math.max(-1, Math.min(1, p[2]))) * R2D$
|
|
8099
|
+
Math.atan2(p[1], p[0]) * R2D$3,
|
|
8100
|
+
Math.asin(Math.max(-1, Math.min(1, p[2]))) * R2D$3
|
|
8019
8101
|
];
|
|
8020
8102
|
}
|
|
8021
8103
|
|
|
@@ -8068,21 +8150,21 @@
|
|
|
8068
8150
|
* equations, not Imago's power-law approximation.
|
|
8069
8151
|
*/
|
|
8070
8152
|
|
|
8071
|
-
var D2R$
|
|
8072
|
-
var R2D$
|
|
8153
|
+
var D2R$2 = Math.PI / 180;
|
|
8154
|
+
var R2D$2 = 180 / Math.PI;
|
|
8073
8155
|
var HALF_PI = Math.PI / 2;
|
|
8074
|
-
var SQRT2 = Math.sqrt(2);
|
|
8075
|
-
var SQRT3 = Math.sqrt(3);
|
|
8076
|
-
var ASIN_ONE_THIRD = Math.asin(1 / 3);
|
|
8156
|
+
var SQRT2$1 = Math.sqrt(2);
|
|
8157
|
+
var SQRT3$1 = Math.sqrt(3);
|
|
8158
|
+
var ASIN_ONE_THIRD$1 = Math.asin(1 / 3);
|
|
8077
8159
|
var EDGE_SCALE = Math.acos(-1 / 3) / 2;
|
|
8078
|
-
var XMIN = -2 * SQRT3;
|
|
8079
|
-
var XMAX = 2 * SQRT3;
|
|
8160
|
+
var XMIN = -2 * SQRT3$1;
|
|
8161
|
+
var XMAX = 2 * SQRT3$1;
|
|
8080
8162
|
var YMIN = -1.5;
|
|
8081
8163
|
var YMAX = 1.5;
|
|
8082
|
-
var BLOCK_HEIGHT = 2 * SQRT3;
|
|
8164
|
+
var BLOCK_HEIGHT = 2 * SQRT3$1;
|
|
8083
8165
|
var LAYOUT_SHIFT = 1.16;
|
|
8084
|
-
var EPS = 1e-12;
|
|
8085
|
-
var engines = {};
|
|
8166
|
+
var EPS$1 = 1e-12;
|
|
8167
|
+
var engines$1 = {};
|
|
8086
8168
|
|
|
8087
8169
|
// The four tetrahedron vertices published by Narukawa, in latitude-longitude
|
|
8088
8170
|
// order. The extra precision preserves the regular tetrahedron to about 1e-9
|
|
@@ -8097,10 +8179,10 @@
|
|
|
8097
8179
|
// D3 Imago's vertex-oriented tetrahedral block. Each entry contains the
|
|
8098
8180
|
// spherical center, local meridian, planar rotation and planar center.
|
|
8099
8181
|
var FACET_DEFS = [
|
|
8100
|
-
[0, SQRT3, HALF_PI, 0, 0, -HALF_PI],
|
|
8101
|
-
[0, -SQRT3, -ASIN_ONE_THIRD, 0, Math.PI, HALF_PI],
|
|
8102
|
-
[3, 0, -ASIN_ONE_THIRD, 2 * Math.PI / 3, Math.PI, 5 * Math.PI / 6],
|
|
8103
|
-
[-3, 0, -ASIN_ONE_THIRD, -2 * Math.PI / 3, Math.PI, Math.PI / 6]
|
|
8182
|
+
[0, SQRT3$1, HALF_PI, 0, 0, -HALF_PI],
|
|
8183
|
+
[0, -SQRT3$1, -ASIN_ONE_THIRD$1, 0, Math.PI, HALF_PI],
|
|
8184
|
+
[3, 0, -ASIN_ONE_THIRD$1, 2 * Math.PI / 3, Math.PI, 5 * Math.PI / 6],
|
|
8185
|
+
[-3, 0, -ASIN_ONE_THIRD$1, -2 * Math.PI / 3, Math.PI, Math.PI / 6]
|
|
8104
8186
|
];
|
|
8105
8187
|
|
|
8106
8188
|
function registerNarukawa2022Projection(mproj) {
|
|
@@ -8111,10 +8193,10 @@
|
|
|
8111
8193
|
}
|
|
8112
8194
|
|
|
8113
8195
|
function getNarukawa2022Engine() {
|
|
8114
|
-
if (!engines.default) {
|
|
8115
|
-
engines.default = createNarukawa2022Engine();
|
|
8196
|
+
if (!engines$1.default) {
|
|
8197
|
+
engines$1.default = createNarukawa2022Engine();
|
|
8116
8198
|
}
|
|
8117
|
-
return engines.default;
|
|
8199
|
+
return engines$1.default;
|
|
8118
8200
|
}
|
|
8119
8201
|
|
|
8120
8202
|
function initNarukawa2022(P) {
|
|
@@ -8126,7 +8208,7 @@
|
|
|
8126
8208
|
xy.x = p[0];
|
|
8127
8209
|
xy.y = p[1];
|
|
8128
8210
|
};
|
|
8129
|
-
P.__projection_topology = engine.getTopology(P.lam0 * R2D$
|
|
8211
|
+
P.__projection_topology = engine.getTopology(P.lam0 * R2D$2);
|
|
8130
8212
|
P.__projected_outline = engine.outline;
|
|
8131
8213
|
}
|
|
8132
8214
|
|
|
@@ -8143,6 +8225,13 @@
|
|
|
8143
8225
|
rotation: def[5]
|
|
8144
8226
|
};
|
|
8145
8227
|
});
|
|
8228
|
+
var rasterSectors = facets.reduce(function(memo, facet) {
|
|
8229
|
+
return memo.concat(getRawFacetSectorBoundaries(facets, facet));
|
|
8230
|
+
}, []);
|
|
8231
|
+
var rasterPieces = createNarukawaRasterPieces(facets, rasterSectors);
|
|
8232
|
+
var rasterPieceIndex = new Map(rasterPieces.map(function(piece) {
|
|
8233
|
+
return [piece.key, piece.id];
|
|
8234
|
+
}));
|
|
8146
8235
|
var outline = [[
|
|
8147
8236
|
[XMIN * EDGE_SCALE, YMIN * EDGE_SCALE],
|
|
8148
8237
|
[XMAX * EDGE_SCALE, YMIN * EDGE_SCALE],
|
|
@@ -8155,6 +8244,7 @@
|
|
|
8155
8244
|
forward: forward,
|
|
8156
8245
|
inverse: inverse,
|
|
8157
8246
|
outline: outline,
|
|
8247
|
+
rasterPieces: rasterPieces,
|
|
8158
8248
|
getTopology: getTopology
|
|
8159
8249
|
};
|
|
8160
8250
|
|
|
@@ -8188,6 +8278,41 @@
|
|
|
8188
8278
|
}],
|
|
8189
8279
|
findRegion: findRegion,
|
|
8190
8280
|
findTransitionRegion: findRegion,
|
|
8281
|
+
raster_regions: rasterPieces.map(function(piece) {
|
|
8282
|
+
return {
|
|
8283
|
+
id: piece.id,
|
|
8284
|
+
facet: piece.facet,
|
|
8285
|
+
sector: piece.sector,
|
|
8286
|
+
source_region: piece.facet * 3 + piece.sector,
|
|
8287
|
+
projected_boundary: piece.boundary.map(function(p) {
|
|
8288
|
+
return [p[0] * EDGE_SCALE, p[1] * EDGE_SCALE];
|
|
8289
|
+
})
|
|
8290
|
+
};
|
|
8291
|
+
}),
|
|
8292
|
+
raster_source_regions: rasterSectors.map(function(sector) {
|
|
8293
|
+
return {
|
|
8294
|
+
id: sector.facet * 3 + sector.sector,
|
|
8295
|
+
source_region: sector.facet * 3 + sector.sector,
|
|
8296
|
+
facet: sector.facet,
|
|
8297
|
+
sector: sector.sector,
|
|
8298
|
+
boundary: sector.sphericalBoundary.map(function(p) {
|
|
8299
|
+
var q = fromCanonical(p[0], p[1], orientation);
|
|
8300
|
+
return [
|
|
8301
|
+
normalizeLongitude$2(q[0] * R2D$2 + lon0),
|
|
8302
|
+
q[1] * R2D$2
|
|
8303
|
+
];
|
|
8304
|
+
})
|
|
8305
|
+
};
|
|
8306
|
+
}),
|
|
8307
|
+
raster_mesh_interval: 32,
|
|
8308
|
+
raster_cell_halo: false,
|
|
8309
|
+
fill_raster_mask: true,
|
|
8310
|
+
fill_raster_coverage: true,
|
|
8311
|
+
findRasterRegion: findRasterRegion,
|
|
8312
|
+
projectRasterRegion: projectRasterRegion,
|
|
8313
|
+
projectRasterSourceRegion: projectRasterSourceRegion,
|
|
8314
|
+
projectRasterSector: projectRasterSector,
|
|
8315
|
+
clipRasterRegionPolygon: clipRasterRegionPolygon,
|
|
8191
8316
|
outline: outline.map(function(ring) {
|
|
8192
8317
|
return ring.map(function(p) {
|
|
8193
8318
|
return p.concat();
|
|
@@ -8196,30 +8321,422 @@
|
|
|
8196
8321
|
};
|
|
8197
8322
|
|
|
8198
8323
|
function findRegion(lon, lat) {
|
|
8199
|
-
var lam = normalizeRadians((lon - lon0) * D2R$
|
|
8200
|
-
return projectState(lam, lat * D2R$
|
|
8324
|
+
var lam = normalizeRadians((lon - lon0) * D2R$2);
|
|
8325
|
+
return projectState(lam, lat * D2R$2).region;
|
|
8326
|
+
}
|
|
8327
|
+
|
|
8328
|
+
function findRasterRegion(lon, lat) {
|
|
8329
|
+
var lam = normalizeRadians((lon - lon0) * D2R$2);
|
|
8330
|
+
var p = toCanonical(lam, lat * D2R$2, orientation);
|
|
8331
|
+
var facet = findForwardFacet(p[0], p[1], facets);
|
|
8332
|
+
var state = applyConditionalLayout(projectFacetRaw(p[0], p[1], facet), facet);
|
|
8333
|
+
return rasterPieceIndex.get(getRasterPieceKey(
|
|
8334
|
+
state.facet, state.sector, state.oobKey, state.folded, state.wrap
|
|
8335
|
+
));
|
|
8336
|
+
}
|
|
8337
|
+
|
|
8338
|
+
function projectRasterRegion(lon, lat, regionId) {
|
|
8339
|
+
var piece = rasterPieces[regionId];
|
|
8340
|
+
var lam = normalizeRadians((lon - lon0) * D2R$2);
|
|
8341
|
+
var p = toCanonical(lam, lat * D2R$2, orientation);
|
|
8342
|
+
var facet = facets[piece.facet];
|
|
8343
|
+
var raw = projectFacetRaw(p[0], p[1], facet, piece.sector);
|
|
8344
|
+
var q = applyRasterPieceLayout(raw, facet, piece);
|
|
8345
|
+
return [q[0] * EDGE_SCALE, q[1] * EDGE_SCALE];
|
|
8346
|
+
}
|
|
8347
|
+
|
|
8348
|
+
function projectRasterSector(lon, lat, facetId, sector) {
|
|
8349
|
+
var lam = normalizeRadians((lon - lon0) * D2R$2);
|
|
8350
|
+
var p = toCanonical(lam, lat * D2R$2, orientation);
|
|
8351
|
+
var raw = projectFacetRaw(p[0], p[1], facets[facetId], sector);
|
|
8352
|
+
return [raw.x, raw.y];
|
|
8353
|
+
}
|
|
8354
|
+
|
|
8355
|
+
function projectRasterSourceRegion(lon, lat, sourceRegionId) {
|
|
8356
|
+
return projectRasterSector(
|
|
8357
|
+
lon, lat, Math.floor(sourceRegionId / 3), sourceRegionId % 3);
|
|
8358
|
+
}
|
|
8359
|
+
|
|
8360
|
+
function clipRasterRegionPolygon(vertices, regionId) {
|
|
8361
|
+
return clipRasterPiecePolygon(
|
|
8362
|
+
vertices, facets[rasterPieces[regionId].facet],
|
|
8363
|
+
rasterPieces[regionId]);
|
|
8364
|
+
}
|
|
8365
|
+
}
|
|
8366
|
+
}
|
|
8367
|
+
|
|
8368
|
+
function createNarukawaRasterPieces(facets, rasterSectors) {
|
|
8369
|
+
var pieces = [];
|
|
8370
|
+
facets.forEach(function(facet) {
|
|
8371
|
+
rasterSectors.filter(function(o) {
|
|
8372
|
+
return o.facet == facet.id;
|
|
8373
|
+
}).forEach(function(sectorData) {
|
|
8374
|
+
['normal', 'xpos', 'xneg', 'ypos', 'yneg'].forEach(function(oobKey) {
|
|
8375
|
+
var oobPolygon = clipOobPolygon(sectorData.boundary, oobKey);
|
|
8376
|
+
if (oobPolygon.length < 3) return;
|
|
8377
|
+
oobPolygon = oobPolygon.map(function(p) {
|
|
8378
|
+
return applyOobTransform(p, facet, oobKey);
|
|
8379
|
+
});
|
|
8380
|
+
[0, 1].forEach(function(folded) {
|
|
8381
|
+
var foldedPolygon = clipPolygonAxis$1(oobPolygon, 0, 0, folded == 0);
|
|
8382
|
+
if (foldedPolygon.length < 3) return;
|
|
8383
|
+
foldedPolygon = foldedPolygon.map(function(p) {
|
|
8384
|
+
return applyFoldTransform(p, folded);
|
|
8385
|
+
});
|
|
8386
|
+
[0, 1].forEach(function(wrap) {
|
|
8387
|
+
var finalPolygon = foldedPolygon.map(function(p) {
|
|
8388
|
+
return [
|
|
8389
|
+
p[0] + LAYOUT_SHIFT + wrap * 2 * BLOCK_HEIGHT - BLOCK_HEIGHT,
|
|
8390
|
+
p[1] + 1.5
|
|
8391
|
+
];
|
|
8392
|
+
});
|
|
8393
|
+
finalPolygon = clipRectangle(
|
|
8394
|
+
finalPolygon, XMIN, YMIN, XMAX, YMAX);
|
|
8395
|
+
if (finalPolygon.length < 3 ||
|
|
8396
|
+
Math.abs(getPlanarRingArea(finalPolygon)) < EPS$1) return;
|
|
8397
|
+
var id = pieces.length;
|
|
8398
|
+
pieces.push({
|
|
8399
|
+
id: id,
|
|
8400
|
+
key: getRasterPieceKey(
|
|
8401
|
+
facet.id, sectorData.sector, oobKey, folded, wrap),
|
|
8402
|
+
facet: facet.id,
|
|
8403
|
+
sector: sectorData.sector,
|
|
8404
|
+
oobKey: oobKey,
|
|
8405
|
+
folded: folded,
|
|
8406
|
+
wrap: wrap,
|
|
8407
|
+
boundary: finalPolygon.concat([finalPolygon[0].concat()])
|
|
8408
|
+
});
|
|
8409
|
+
});
|
|
8410
|
+
});
|
|
8411
|
+
});
|
|
8412
|
+
});
|
|
8413
|
+
});
|
|
8414
|
+
return pieces;
|
|
8415
|
+
}
|
|
8416
|
+
|
|
8417
|
+
function getRawFacetSectorBoundaries(facets, facet) {
|
|
8418
|
+
var corners = facets.filter(function(o) {
|
|
8419
|
+
return o.id != facet.id;
|
|
8420
|
+
}).map(function(o) {
|
|
8421
|
+
var v = radiansToVector(o.lon, o.lat);
|
|
8422
|
+
return vectorToRadians([-v[0], -v[1], -v[2]]);
|
|
8423
|
+
});
|
|
8424
|
+
corners.sort(function(a, b) {
|
|
8425
|
+
return obliquifySpherical(a[1], a[0], facet)[1] -
|
|
8426
|
+
obliquifySpherical(b[1], b[0], facet)[1];
|
|
8427
|
+
});
|
|
8428
|
+
var samples = [];
|
|
8429
|
+
for (var i = 0; i < corners.length; i++) {
|
|
8430
|
+
var edge = interpolateSphericalRadians(
|
|
8431
|
+
corners[i], corners[(i + 1) % corners.length], 0.05 * D2R$2);
|
|
8432
|
+
for (var j = 0; j < edge.length - 1; j++) {
|
|
8433
|
+
var p = edge[j];
|
|
8434
|
+
var q = projectFacetRaw(p[0], p[1], facet);
|
|
8435
|
+
samples.push({
|
|
8436
|
+
sector: q.sector,
|
|
8437
|
+
point: [q.x, q.y],
|
|
8438
|
+
spherical: p.concat()
|
|
8439
|
+
});
|
|
8440
|
+
}
|
|
8441
|
+
}
|
|
8442
|
+
return [0, 1, 2].map(function(sector) {
|
|
8443
|
+
var run = getLongestCircularSectorRun(samples, sector);
|
|
8444
|
+
var middle = getFarthestSphericalSample(
|
|
8445
|
+
run, [facet.lon, facet.lat]);
|
|
8446
|
+
return {
|
|
8447
|
+
facet: facet.id,
|
|
8448
|
+
sector: sector,
|
|
8449
|
+
sphericalBoundary: [
|
|
8450
|
+
[facet.lon, facet.lat],
|
|
8451
|
+
run[0].spherical,
|
|
8452
|
+
middle.spherical,
|
|
8453
|
+
run[run.length - 1].spherical,
|
|
8454
|
+
[facet.lon, facet.lat]
|
|
8455
|
+
],
|
|
8456
|
+
boundary: [[facet.x, facet.y]].concat(run.map(function(o) {
|
|
8457
|
+
return o.point;
|
|
8458
|
+
}))
|
|
8459
|
+
};
|
|
8460
|
+
});
|
|
8461
|
+
}
|
|
8462
|
+
|
|
8463
|
+
function getFarthestSphericalSample(samples, center) {
|
|
8464
|
+
var centerVector = radiansToVector(center[0], center[1]);
|
|
8465
|
+
var best = samples[0];
|
|
8466
|
+
var minDot = Infinity;
|
|
8467
|
+
samples.forEach(function(sample) {
|
|
8468
|
+
var v = radiansToVector(sample.spherical[0], sample.spherical[1]);
|
|
8469
|
+
var d = dot$1(centerVector, v);
|
|
8470
|
+
if (d < minDot) {
|
|
8471
|
+
minDot = d;
|
|
8472
|
+
best = sample;
|
|
8473
|
+
}
|
|
8474
|
+
});
|
|
8475
|
+
return best;
|
|
8476
|
+
}
|
|
8477
|
+
|
|
8478
|
+
function getLongestCircularSectorRun(samples, sector) {
|
|
8479
|
+
var runs = [];
|
|
8480
|
+
var run = [];
|
|
8481
|
+
for (var i = 0; i < samples.length * 2; i++) {
|
|
8482
|
+
var sample = samples[i % samples.length];
|
|
8483
|
+
if (sample.sector == sector) {
|
|
8484
|
+
run.push(sample);
|
|
8485
|
+
} else if (run.length) {
|
|
8486
|
+
runs.push(run);
|
|
8487
|
+
run = [];
|
|
8488
|
+
}
|
|
8489
|
+
}
|
|
8490
|
+
if (run.length) runs.push(run);
|
|
8491
|
+
runs.sort(function(a, b) { return b.length - a.length; });
|
|
8492
|
+
run = runs[0] || [];
|
|
8493
|
+
if (run.length > samples.length) run = run.slice(0, samples.length);
|
|
8494
|
+
return run;
|
|
8495
|
+
}
|
|
8496
|
+
|
|
8497
|
+
function applyRasterPieceLayout(raw, facet, piece) {
|
|
8498
|
+
var p = applyOobTransform([raw.x, raw.y], facet, piece.oobKey);
|
|
8499
|
+
p = applyFoldTransform(p, piece.folded);
|
|
8500
|
+
return [
|
|
8501
|
+
p[0] + LAYOUT_SHIFT + piece.wrap * 2 * BLOCK_HEIGHT - BLOCK_HEIGHT,
|
|
8502
|
+
p[1] + 1.5
|
|
8503
|
+
];
|
|
8504
|
+
}
|
|
8505
|
+
|
|
8506
|
+
function clipRasterPiecePolygon(vertices, facet, piece) {
|
|
8507
|
+
var polygon = clipRasterOobPolygon(vertices, piece.oobKey);
|
|
8508
|
+
polygon = polygon.map(function(vertex) {
|
|
8509
|
+
var p = applyOobTransform([vertex.x, vertex.y], facet, piece.oobKey);
|
|
8510
|
+
return copyRasterVertex$1(vertex, p[0], p[1]);
|
|
8511
|
+
});
|
|
8512
|
+
polygon = clipRasterPolygonAxis$1(
|
|
8513
|
+
polygon, 'x', 0, piece.folded == 0);
|
|
8514
|
+
polygon = polygon.map(function(vertex) {
|
|
8515
|
+
var p = applyFoldTransform([vertex.x, vertex.y], piece.folded);
|
|
8516
|
+
return copyRasterVertex$1(vertex, p[0], p[1]);
|
|
8517
|
+
});
|
|
8518
|
+
polygon = polygon.map(function(vertex) {
|
|
8519
|
+
return copyRasterVertex$1(
|
|
8520
|
+
vertex,
|
|
8521
|
+
vertex.x + LAYOUT_SHIFT +
|
|
8522
|
+
piece.wrap * 2 * BLOCK_HEIGHT - BLOCK_HEIGHT,
|
|
8523
|
+
vertex.y + 1.5
|
|
8524
|
+
);
|
|
8525
|
+
});
|
|
8526
|
+
polygon = clipRasterPolygonAxis$1(polygon, 'x', XMIN, true);
|
|
8527
|
+
polygon = clipRasterPolygonAxis$1(polygon, 'x', XMAX, false);
|
|
8528
|
+
polygon = clipRasterPolygonAxis$1(polygon, 'y', YMIN, true);
|
|
8529
|
+
polygon = clipRasterPolygonAxis$1(polygon, 'y', YMAX, false);
|
|
8530
|
+
polygon.forEach(function(vertex) {
|
|
8531
|
+
vertex.x *= EDGE_SCALE;
|
|
8532
|
+
vertex.y *= EDGE_SCALE;
|
|
8533
|
+
});
|
|
8534
|
+
return polygon;
|
|
8535
|
+
}
|
|
8536
|
+
|
|
8537
|
+
function clipRasterOobPolygon(polygon, oobKey) {
|
|
8538
|
+
if (oobKey == 'xpos') {
|
|
8539
|
+
return clipRasterPolygonAxis$1(polygon, 'x', 3, true);
|
|
8540
|
+
}
|
|
8541
|
+
if (oobKey == 'xneg') {
|
|
8542
|
+
return clipRasterPolygonAxis$1(polygon, 'x', -3, false);
|
|
8543
|
+
}
|
|
8544
|
+
if (oobKey == 'ypos' || oobKey == 'yneg') {
|
|
8545
|
+
polygon = clipRasterPolygonAxis$1(polygon, 'x', -3, true);
|
|
8546
|
+
polygon = clipRasterPolygonAxis$1(polygon, 'x', 3, false);
|
|
8547
|
+
return clipRasterPolygonAxis$1(
|
|
8548
|
+
polygon, 'y', oobKey == 'ypos' ? SQRT3$1 : -SQRT3$1,
|
|
8549
|
+
oobKey == 'ypos');
|
|
8550
|
+
}
|
|
8551
|
+
polygon = clipRasterPolygonAxis$1(polygon, 'x', -3, true);
|
|
8552
|
+
polygon = clipRasterPolygonAxis$1(polygon, 'x', 3, false);
|
|
8553
|
+
polygon = clipRasterPolygonAxis$1(polygon, 'y', -SQRT3$1, true);
|
|
8554
|
+
return clipRasterPolygonAxis$1(polygon, 'y', SQRT3$1, false);
|
|
8555
|
+
}
|
|
8556
|
+
|
|
8557
|
+
function clipRasterPolygonAxis$1(polygon, axis, value, keepGreater) {
|
|
8558
|
+
var output = [];
|
|
8559
|
+
if (polygon.length === 0) return output;
|
|
8560
|
+
var a = polygon[polygon.length - 1];
|
|
8561
|
+
var aInside = keepGreater ?
|
|
8562
|
+
a[axis] >= value - EPS$1 : a[axis] <= value + EPS$1;
|
|
8563
|
+
polygon.forEach(function(b) {
|
|
8564
|
+
var bInside = keepGreater ?
|
|
8565
|
+
b[axis] >= value - EPS$1 : b[axis] <= value + EPS$1;
|
|
8566
|
+
if (aInside != bInside) {
|
|
8567
|
+
var t = (value - a[axis]) / (b[axis] - a[axis]);
|
|
8568
|
+
var vertex = {
|
|
8569
|
+
x: a.x + (b.x - a.x) * t,
|
|
8570
|
+
y: a.y + (b.y - a.y) * t,
|
|
8571
|
+
sx: a.sx + (b.sx - a.sx) * t,
|
|
8572
|
+
sy: a.sy + (b.sy - a.sy) * t,
|
|
8573
|
+
lon: a.lon + (b.lon - a.lon) * t,
|
|
8574
|
+
lat: a.lat + (b.lat - a.lat) * t
|
|
8575
|
+
};
|
|
8576
|
+
vertex[axis] = value;
|
|
8577
|
+
output.push(vertex);
|
|
8201
8578
|
}
|
|
8579
|
+
if (bInside) output.push(copyRasterVertex$1(b, b.x, b.y));
|
|
8580
|
+
a = b;
|
|
8581
|
+
aInside = bInside;
|
|
8582
|
+
});
|
|
8583
|
+
return output;
|
|
8584
|
+
}
|
|
8585
|
+
|
|
8586
|
+
function copyRasterVertex$1(vertex, x, y) {
|
|
8587
|
+
return {
|
|
8588
|
+
x: x,
|
|
8589
|
+
y: y,
|
|
8590
|
+
sx: vertex.sx,
|
|
8591
|
+
sy: vertex.sy,
|
|
8592
|
+
lon: vertex.lon,
|
|
8593
|
+
lat: vertex.lat
|
|
8594
|
+
};
|
|
8595
|
+
}
|
|
8596
|
+
|
|
8597
|
+
function applyOobTransform(p, facet, oobKey) {
|
|
8598
|
+
if (oobKey == 'xpos' || oobKey == 'xneg') {
|
|
8599
|
+
return [2 * facet.x - p[0], -p[1]];
|
|
8202
8600
|
}
|
|
8601
|
+
if (oobKey == 'ypos') {
|
|
8602
|
+
return [-p[0], BLOCK_HEIGHT - p[1]];
|
|
8603
|
+
}
|
|
8604
|
+
if (oobKey == 'yneg') {
|
|
8605
|
+
return [-p[0], -BLOCK_HEIGHT - p[1]];
|
|
8606
|
+
}
|
|
8607
|
+
return p.concat();
|
|
8608
|
+
}
|
|
8609
|
+
|
|
8610
|
+
function applyFoldTransform(p, folded) {
|
|
8611
|
+
return folded ? [BLOCK_HEIGHT - p[1], p[0]] : [p[1], -p[0]];
|
|
8612
|
+
}
|
|
8613
|
+
|
|
8614
|
+
function clipOobPolygon(polygon, oobKey) {
|
|
8615
|
+
if (oobKey == 'xpos') return clipPolygonAxis$1(polygon, 0, 3, true);
|
|
8616
|
+
if (oobKey == 'xneg') return clipPolygonAxis$1(polygon, 0, -3, false);
|
|
8617
|
+
if (oobKey == 'ypos') {
|
|
8618
|
+
return clipPolygonAxis$1(
|
|
8619
|
+
clipPolygonAxis$1(
|
|
8620
|
+
clipPolygonAxis$1(polygon, 0, -3, true), 0, 3, false),
|
|
8621
|
+
1, SQRT3$1, true);
|
|
8622
|
+
}
|
|
8623
|
+
if (oobKey == 'yneg') {
|
|
8624
|
+
return clipPolygonAxis$1(
|
|
8625
|
+
clipPolygonAxis$1(
|
|
8626
|
+
clipPolygonAxis$1(polygon, 0, -3, true), 0, 3, false),
|
|
8627
|
+
1, -SQRT3$1, false);
|
|
8628
|
+
}
|
|
8629
|
+
return clipRectangle(polygon, -3, -SQRT3$1, 3, SQRT3$1);
|
|
8630
|
+
}
|
|
8631
|
+
|
|
8632
|
+
function clipRectangle(polygon, xmin, ymin, xmax, ymax) {
|
|
8633
|
+
polygon = clipPolygonAxis$1(polygon, 0, xmin, true);
|
|
8634
|
+
polygon = clipPolygonAxis$1(polygon, 0, xmax, false);
|
|
8635
|
+
polygon = clipPolygonAxis$1(polygon, 1, ymin, true);
|
|
8636
|
+
return clipPolygonAxis$1(polygon, 1, ymax, false);
|
|
8637
|
+
}
|
|
8638
|
+
|
|
8639
|
+
function clipPolygonAxis$1(polygon, axis, value, keepGreater) {
|
|
8640
|
+
var output = [];
|
|
8641
|
+
if (polygon.length === 0) return output;
|
|
8642
|
+
var a = polygon[polygon.length - 1];
|
|
8643
|
+
var aInside = keepGreater ? a[axis] >= value - EPS$1 : a[axis] <= value + EPS$1;
|
|
8644
|
+
polygon.forEach(function(b) {
|
|
8645
|
+
var bInside = keepGreater ? b[axis] >= value - EPS$1 : b[axis] <= value + EPS$1;
|
|
8646
|
+
if (aInside != bInside) {
|
|
8647
|
+
var t = (value - a[axis]) / (b[axis] - a[axis]);
|
|
8648
|
+
var p = [
|
|
8649
|
+
a[0] + (b[0] - a[0]) * t,
|
|
8650
|
+
a[1] + (b[1] - a[1]) * t
|
|
8651
|
+
];
|
|
8652
|
+
p[axis] = value;
|
|
8653
|
+
output.push(p);
|
|
8654
|
+
}
|
|
8655
|
+
if (bInside) output.push(b.concat());
|
|
8656
|
+
a = b;
|
|
8657
|
+
aInside = bInside;
|
|
8658
|
+
});
|
|
8659
|
+
return output;
|
|
8660
|
+
}
|
|
8661
|
+
|
|
8662
|
+
function interpolateSphericalRadians(a, b, interval) {
|
|
8663
|
+
var av = radiansToVector(a[0], a[1]);
|
|
8664
|
+
var bv = radiansToVector(b[0], b[1]);
|
|
8665
|
+
var angle = Math.acos(clamp$3(dot$1(av, bv), -1, 1));
|
|
8666
|
+
var count = Math.max(1, Math.ceil(angle / interval));
|
|
8667
|
+
var sinAngle = Math.sin(angle);
|
|
8668
|
+
var points = [];
|
|
8669
|
+
for (var i = 0; i <= count; i++) {
|
|
8670
|
+
var t = i / count;
|
|
8671
|
+
var ka = Math.sin((1 - t) * angle) / sinAngle;
|
|
8672
|
+
var kb = Math.sin(t * angle) / sinAngle;
|
|
8673
|
+
points.push(vectorToRadians(normalizeVector([
|
|
8674
|
+
av[0] * ka + bv[0] * kb,
|
|
8675
|
+
av[1] * ka + bv[1] * kb,
|
|
8676
|
+
av[2] * ka + bv[2] * kb
|
|
8677
|
+
])));
|
|
8678
|
+
}
|
|
8679
|
+
return points;
|
|
8680
|
+
}
|
|
8681
|
+
|
|
8682
|
+
function vectorToRadians(p) {
|
|
8683
|
+
return [
|
|
8684
|
+
Math.atan2(p[1], p[0]),
|
|
8685
|
+
Math.asin(clamp$3(p[2], -1, 1))
|
|
8686
|
+
];
|
|
8687
|
+
}
|
|
8688
|
+
|
|
8689
|
+
function getPlanarRingArea(ring) {
|
|
8690
|
+
var area = 0;
|
|
8691
|
+
for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
8692
|
+
area += ring[j][0] * ring[i][1] - ring[i][0] * ring[j][1];
|
|
8693
|
+
}
|
|
8694
|
+
return area / 2;
|
|
8695
|
+
}
|
|
8696
|
+
|
|
8697
|
+
function getRasterPieceKey(facet, sector, oobKey, folded, wrap) {
|
|
8698
|
+
return [facet, sector, oobKey, folded, wrap].join(':');
|
|
8203
8699
|
}
|
|
8204
8700
|
|
|
8205
8701
|
function projectCanonical(lam, phi, facets) {
|
|
8206
8702
|
var facet = findForwardFacet(lam, phi, facets);
|
|
8703
|
+
var state = projectFacetRaw(lam, phi, facet);
|
|
8704
|
+
return applyConditionalLayout(state, facet);
|
|
8705
|
+
}
|
|
8706
|
+
|
|
8707
|
+
function projectFacetRaw(lam, phi, facet, forcedSector) {
|
|
8207
8708
|
var relative = obliquifySpherical(phi, lam, facet);
|
|
8208
|
-
var sector =
|
|
8709
|
+
var sector = forcedSector == null ?
|
|
8710
|
+
Math.floor((relative[1] + Math.PI / 3) / (2 * Math.PI / 3)) :
|
|
8711
|
+
forcedSector == 2 ? -1 : forcedSector;
|
|
8209
8712
|
var base = sector * 2 * Math.PI / 3;
|
|
8210
8713
|
var polar = narukawaFaceForward(relative[1] - base, relative[0]);
|
|
8211
8714
|
var angle = polar[1] + facet.rotation + base / 2;
|
|
8212
8715
|
var x = polar[0] * Math.cos(angle) + facet.x;
|
|
8213
8716
|
var y = polar[0] * Math.sin(angle) + facet.y;
|
|
8717
|
+
return {
|
|
8718
|
+
x: x,
|
|
8719
|
+
y: y,
|
|
8720
|
+
facet: facet.id,
|
|
8721
|
+
sector: mod(sector, 3)
|
|
8722
|
+
};
|
|
8723
|
+
}
|
|
8724
|
+
|
|
8725
|
+
function applyConditionalLayout(raw, facet) {
|
|
8726
|
+
var x = raw.x;
|
|
8727
|
+
var y = raw.y;
|
|
8214
8728
|
var oob = 0;
|
|
8729
|
+
var oobKey = 'normal';
|
|
8215
8730
|
var folded = 0;
|
|
8216
8731
|
var wrap = 0;
|
|
8217
8732
|
|
|
8218
|
-
if (Math.abs(x) > 3 + EPS) {
|
|
8733
|
+
if (Math.abs(x) > 3 + EPS$1) {
|
|
8734
|
+
oobKey = x > 0 ? 'xpos' : 'xneg';
|
|
8219
8735
|
x = 2 * facet.x - x;
|
|
8220
8736
|
y = -y;
|
|
8221
8737
|
oob = 1;
|
|
8222
|
-
} else if (Math.abs(y) > SQRT3 + EPS) {
|
|
8738
|
+
} else if (Math.abs(y) > SQRT3$1 + EPS$1) {
|
|
8739
|
+
oobKey = y > 0 ? 'ypos' : 'yneg';
|
|
8223
8740
|
x = -x;
|
|
8224
8741
|
y = BLOCK_HEIGHT * Math.sign(y) - y;
|
|
8225
8742
|
oob = 2;
|
|
@@ -8227,7 +8744,7 @@
|
|
|
8227
8744
|
|
|
8228
8745
|
var qx = y;
|
|
8229
8746
|
var qy = -x;
|
|
8230
|
-
if (qy > EPS) {
|
|
8747
|
+
if (qy > EPS$1) {
|
|
8231
8748
|
qx = BLOCK_HEIGHT - qx;
|
|
8232
8749
|
qy = -qy;
|
|
8233
8750
|
folded = 1;
|
|
@@ -8239,14 +8756,15 @@
|
|
|
8239
8756
|
}
|
|
8240
8757
|
x = qx - BLOCK_HEIGHT;
|
|
8241
8758
|
y = qy + 1.5;
|
|
8242
|
-
x = clamp$
|
|
8243
|
-
y = clamp$
|
|
8759
|
+
x = clamp$3(x, XMIN, XMAX);
|
|
8760
|
+
y = clamp$3(y, YMIN, YMAX);
|
|
8244
8761
|
return {
|
|
8245
8762
|
x: x,
|
|
8246
8763
|
y: y,
|
|
8247
|
-
facet: facet
|
|
8248
|
-
sector:
|
|
8764
|
+
facet: raw.facet,
|
|
8765
|
+
sector: raw.sector,
|
|
8249
8766
|
oob: oob,
|
|
8767
|
+
oobKey: oobKey,
|
|
8250
8768
|
folded: folded,
|
|
8251
8769
|
wrap: wrap
|
|
8252
8770
|
};
|
|
@@ -8267,29 +8785,29 @@
|
|
|
8267
8785
|
}
|
|
8268
8786
|
|
|
8269
8787
|
function narukawaFaceForward(lam, phi) {
|
|
8270
|
-
var a = lam - Math.asin(Math.sin(lam) / SQRT3);
|
|
8271
|
-
var theta = Math.atan(2 * SQRT3 / Math.PI * a);
|
|
8272
|
-
var denominator = 2 + SQRT2 * Math.tan(phi);
|
|
8788
|
+
var a = lam - Math.asin(Math.sin(lam) / SQRT3$1);
|
|
8789
|
+
var theta = Math.atan(2 * SQRT3$1 / Math.PI * a);
|
|
8790
|
+
var denominator = 2 + SQRT2$1 * Math.tan(phi);
|
|
8273
8791
|
var q = denominator > 0 ? (2 + Math.cos(lam)) / denominator : 0;
|
|
8274
|
-
var r = q * SQRT3 / Math.cos(theta);
|
|
8792
|
+
var r = q * SQRT3$1 / Math.cos(theta);
|
|
8275
8793
|
return [r, theta];
|
|
8276
8794
|
}
|
|
8277
8795
|
|
|
8278
8796
|
function narukawaFaceInverse(r, theta) {
|
|
8279
|
-
var target = Math.tan(theta) * Math.PI / (2 * SQRT3);
|
|
8797
|
+
var target = Math.tan(theta) * Math.PI / (2 * SQRT3$1);
|
|
8280
8798
|
var lo = -Math.PI / 3;
|
|
8281
8799
|
var hi = Math.PI / 3;
|
|
8282
8800
|
var lam;
|
|
8283
8801
|
for (var i = 0; i < 55; i++) {
|
|
8284
8802
|
lam = (lo + hi) / 2;
|
|
8285
|
-
var a = lam - Math.asin(Math.sin(lam) / SQRT3);
|
|
8803
|
+
var a = lam - Math.asin(Math.sin(lam) / SQRT3$1);
|
|
8286
8804
|
if (a < target) lo = lam;
|
|
8287
8805
|
else hi = lam;
|
|
8288
8806
|
}
|
|
8289
8807
|
lam = (lo + hi) / 2;
|
|
8290
|
-
var q = r * Math.cos(theta) / SQRT3;
|
|
8291
|
-
var phi = q < EPS ? HALF_PI :
|
|
8292
|
-
Math.atan(((2 + Math.cos(lam)) / q - 2) / SQRT2);
|
|
8808
|
+
var q = r * Math.cos(theta) / SQRT3$1;
|
|
8809
|
+
var phi = q < EPS$1 ? HALF_PI :
|
|
8810
|
+
Math.atan(((2 + Math.cos(lam)) / q - 2) / SQRT2$1);
|
|
8293
8811
|
return [phi, lam];
|
|
8294
8812
|
}
|
|
8295
8813
|
|
|
@@ -8349,7 +8867,7 @@
|
|
|
8349
8867
|
var v = radiansToVector(lam, phi);
|
|
8350
8868
|
return [
|
|
8351
8869
|
Math.atan2(dot$1(v, orientation.y), dot$1(v, orientation.x)),
|
|
8352
|
-
Math.asin(clamp$
|
|
8870
|
+
Math.asin(clamp$3(dot$1(v, orientation.z), -1, 1))
|
|
8353
8871
|
];
|
|
8354
8872
|
}
|
|
8355
8873
|
|
|
@@ -8360,7 +8878,7 @@
|
|
|
8360
8878
|
orientation.x[1] * v[0] + orientation.y[1] * v[1] + orientation.z[1] * v[2],
|
|
8361
8879
|
orientation.x[2] * v[0] + orientation.y[2] * v[1] + orientation.z[2] * v[2]
|
|
8362
8880
|
];
|
|
8363
|
-
return [Math.atan2(p[1], p[0]), Math.asin(clamp$
|
|
8881
|
+
return [Math.atan2(p[1], p[0]), Math.asin(clamp$3(p[2], -1, 1))];
|
|
8364
8882
|
}
|
|
8365
8883
|
|
|
8366
8884
|
// Adapted from Justin Kunimune's Imago implementation.
|
|
@@ -8370,22 +8888,22 @@
|
|
|
8370
8888
|
var theta0 = pole.meridian;
|
|
8371
8889
|
var lat1;
|
|
8372
8890
|
var lon1;
|
|
8373
|
-
if (Math.abs(lat0 - HALF_PI) < EPS) {
|
|
8891
|
+
if (Math.abs(lat0 - HALF_PI) < EPS$1) {
|
|
8374
8892
|
lat1 = lat;
|
|
8375
8893
|
lon1 = lon - lon0;
|
|
8376
8894
|
} else {
|
|
8377
|
-
lat1 = Math.asin(clamp$
|
|
8895
|
+
lat1 = Math.asin(clamp$3(
|
|
8378
8896
|
Math.sin(lat0) * Math.sin(lat) +
|
|
8379
8897
|
Math.cos(lat0) * Math.cos(lat) * Math.cos(lon0 - lon),
|
|
8380
8898
|
-1,
|
|
8381
8899
|
1
|
|
8382
8900
|
));
|
|
8383
8901
|
var denominator = Math.cos(lat1);
|
|
8384
|
-
var value = denominator < EPS ? 1 :
|
|
8902
|
+
var value = denominator < EPS$1 ? 1 :
|
|
8385
8903
|
(Math.cos(lat0) * Math.sin(lat) -
|
|
8386
8904
|
Math.sin(lat0) * Math.cos(lat) * Math.cos(lon0 - lon)) /
|
|
8387
8905
|
denominator;
|
|
8388
|
-
lon1 = Math.acos(clamp$
|
|
8906
|
+
lon1 = Math.acos(clamp$3(value, -1, 1)) - Math.PI;
|
|
8389
8907
|
if (Math.sin(lon - lon0) > 0) lon1 = -lon1;
|
|
8390
8908
|
}
|
|
8391
8909
|
return [lat1, normalizeRadians(lon1 - theta0)];
|
|
@@ -8395,20 +8913,20 @@
|
|
|
8395
8913
|
var lat0 = pole.lat;
|
|
8396
8914
|
var lon0 = pole.lon;
|
|
8397
8915
|
lon += pole.meridian;
|
|
8398
|
-
var latOut = Math.asin(clamp$
|
|
8916
|
+
var latOut = Math.asin(clamp$3(
|
|
8399
8917
|
Math.sin(lat0) * Math.sin(lat) -
|
|
8400
8918
|
Math.cos(lat0) * Math.cos(lon) * Math.cos(lat),
|
|
8401
8919
|
-1,
|
|
8402
8920
|
1
|
|
8403
8921
|
));
|
|
8404
8922
|
var lonOut;
|
|
8405
|
-
if (Math.abs(lat0 - HALF_PI) < EPS) {
|
|
8923
|
+
if (Math.abs(lat0 - HALF_PI) < EPS$1) {
|
|
8406
8924
|
lonOut = lon + lon0;
|
|
8407
8925
|
} else {
|
|
8408
8926
|
var value = Math.sin(lat) / Math.cos(lat0) / Math.cos(latOut) -
|
|
8409
8927
|
Math.tan(lat0) * Math.tan(latOut);
|
|
8410
|
-
if (Math.sin(lon) > 0) lonOut = lon0 + Math.acos(clamp$
|
|
8411
|
-
else lonOut = lon0 - Math.acos(clamp$
|
|
8928
|
+
if (Math.sin(lon) > 0) lonOut = lon0 + Math.acos(clamp$3(value, -1, 1));
|
|
8929
|
+
else lonOut = lon0 - Math.acos(clamp$3(value, -1, 1));
|
|
8412
8930
|
}
|
|
8413
8931
|
return [latOut, normalizeRadians(lonOut)];
|
|
8414
8932
|
}
|
|
@@ -8431,11 +8949,11 @@
|
|
|
8431
8949
|
var y = edge[0][1] + (edge[1][1] - edge[0][1]) * t;
|
|
8432
8950
|
var p = inverse(x * EDGE_SCALE, y * EDGE_SCALE);
|
|
8433
8951
|
path.push([
|
|
8434
|
-
normalizeLongitude$
|
|
8435
|
-
p[1] * R2D$
|
|
8952
|
+
normalizeLongitude$2(p[0] * R2D$2 + lon0),
|
|
8953
|
+
p[1] * R2D$2
|
|
8436
8954
|
]);
|
|
8437
8955
|
}
|
|
8438
|
-
return memo.concat(splitPathAtAntimeridian$
|
|
8956
|
+
return memo.concat(splitPathAtAntimeridian$2(path));
|
|
8439
8957
|
}, []);
|
|
8440
8958
|
return paths.map(function(part) {
|
|
8441
8959
|
part.mask_width = 4e-5;
|
|
@@ -8443,7 +8961,7 @@
|
|
|
8443
8961
|
});
|
|
8444
8962
|
}
|
|
8445
8963
|
|
|
8446
|
-
function splitPathAtAntimeridian$
|
|
8964
|
+
function splitPathAtAntimeridian$2(path) {
|
|
8447
8965
|
var paths = [];
|
|
8448
8966
|
var part = [path[0]];
|
|
8449
8967
|
for (var i = 1; i < path.length; i++) {
|
|
@@ -8479,7 +8997,7 @@
|
|
|
8479
8997
|
}
|
|
8480
8998
|
|
|
8481
8999
|
function latLonToVector(p) {
|
|
8482
|
-
return radiansToVector(p[1] * D2R$
|
|
9000
|
+
return radiansToVector(p[1] * D2R$2, p[0] * D2R$2);
|
|
8483
9001
|
}
|
|
8484
9002
|
|
|
8485
9003
|
function radiansToVector(lam, phi) {
|
|
@@ -8522,13 +9040,13 @@
|
|
|
8522
9040
|
return lam;
|
|
8523
9041
|
}
|
|
8524
9042
|
|
|
8525
|
-
function normalizeLongitude$
|
|
9043
|
+
function normalizeLongitude$2(lon) {
|
|
8526
9044
|
while (lon > 180) lon -= 360;
|
|
8527
9045
|
while (lon < -180) lon += 360;
|
|
8528
9046
|
return lon;
|
|
8529
9047
|
}
|
|
8530
9048
|
|
|
8531
|
-
function clamp$
|
|
9049
|
+
function clamp$3(value, min, max) {
|
|
8532
9050
|
return Math.max(min, Math.min(max, value));
|
|
8533
9051
|
}
|
|
8534
9052
|
|
|
@@ -8538,10 +9056,828 @@
|
|
|
8538
9056
|
registerNarukawa2022Projection: registerNarukawa2022Projection
|
|
8539
9057
|
});
|
|
8540
9058
|
|
|
9059
|
+
/*
|
|
9060
|
+
* Rectangular conformal tetrahedral projections based on L. P. Lee's
|
|
9061
|
+
* conformal face transform.
|
|
9062
|
+
*
|
|
9063
|
+
* Lee transform and tetrahedral net adapted from d3-geo-polygon:
|
|
9064
|
+
* Copyright 2017-2024 Mike Bostock, ISC license.
|
|
9065
|
+
* https://github.com/d3/d3-geo-polygon/blob/main/src/tetrahedralLee.js
|
|
9066
|
+
*
|
|
9067
|
+
* The rectangular layout below is derived from Markley's repeated-face
|
|
9068
|
+
* construction: four affine copies of the triangular Lee net are clipped to
|
|
9069
|
+
* a 4/sqrt(3) frame. See F. Landis Markley, "Tetrahedral Map Projection"
|
|
9070
|
+
* (2020), and https://blog.map-projections.net/lee-markley-calm-and-grieger.
|
|
9071
|
+
*/
|
|
9072
|
+
|
|
9073
|
+
|
|
9074
|
+
var D2R$1 = Math.PI / 180;
|
|
9075
|
+
var R2D$1 = 180 / Math.PI;
|
|
9076
|
+
var SQRT2 = Math.sqrt(2);
|
|
9077
|
+
var SQRT3 = Math.sqrt(3);
|
|
9078
|
+
var ASIN_ONE_THIRD = Math.asin(1 / 3);
|
|
9079
|
+
var MARKLEY_LATITUDE = Math.acos(1 / 3) * 0.5 * R2D$1;
|
|
9080
|
+
var LAYOUT_PERIOD = 8;
|
|
9081
|
+
var MARKLEY_LAYOUT_PHASE = -2;
|
|
9082
|
+
var CALM_LAYOUT_PHASE = -1.5;
|
|
9083
|
+
var RECT_XMIN = -7;
|
|
9084
|
+
var RECT_XMAX = 1;
|
|
9085
|
+
var RECT_YMIN = -2 * SQRT3;
|
|
9086
|
+
var RECT_YMAX = 0;
|
|
9087
|
+
var EPS = 1e-12;
|
|
9088
|
+
var MIN_PIECE_AREA = 1e-6;
|
|
9089
|
+
var engines = {};
|
|
9090
|
+
|
|
9091
|
+
var TETRAHEDRON_VERTICES = [
|
|
9092
|
+
[0, 90],
|
|
9093
|
+
[-180, -ASIN_ONE_THIRD * R2D$1],
|
|
9094
|
+
[-60, -ASIN_ONE_THIRD * R2D$1],
|
|
9095
|
+
[60, -ASIN_ONE_THIRD * R2D$1]
|
|
9096
|
+
];
|
|
9097
|
+
|
|
9098
|
+
var TETRAHEDRON_FACES = [
|
|
9099
|
+
[1, 2, 3],
|
|
9100
|
+
[0, 2, 1],
|
|
9101
|
+
[0, 3, 2],
|
|
9102
|
+
[0, 1, 3]
|
|
9103
|
+
].map(function(face) {
|
|
9104
|
+
return face.map(function(i) {
|
|
9105
|
+
return TETRAHEDRON_VERTICES[i];
|
|
9106
|
+
});
|
|
9107
|
+
});
|
|
9108
|
+
|
|
9109
|
+
var LAYOUT_COPIES = [
|
|
9110
|
+
{id: 0, name: 'green', matrix: [1, 0, 0, 0, -1, 0]},
|
|
9111
|
+
{id: 1, name: 'red', matrix: [-1, 0, -4, 0, 1, 0]},
|
|
9112
|
+
{id: 2, name: 'blue', matrix: [1, 0, -8, 0, -1, 0]},
|
|
9113
|
+
{id: 3, name: 'orange', matrix: [-1, 0, 4, 0, 1, 0]}
|
|
9114
|
+
];
|
|
9115
|
+
|
|
9116
|
+
function registerLeeTetrahedralProjections(mproj) {
|
|
9117
|
+
if (!mproj) return;
|
|
9118
|
+
register('markley', 'Markley conformal tetrahedral world map');
|
|
9119
|
+
register('calm', 'Conformal Authagraph-Like Map');
|
|
9120
|
+
|
|
9121
|
+
function register(id, name) {
|
|
9122
|
+
if (mproj.internal.pj_list[id]) return;
|
|
9123
|
+
mproj.pj_add(function(P) {
|
|
9124
|
+
initLeeTetrahedral(P, id);
|
|
9125
|
+
}, id, name);
|
|
9126
|
+
}
|
|
9127
|
+
}
|
|
9128
|
+
|
|
9129
|
+
function getLeeTetrahedralEngine(id) {
|
|
9130
|
+
id = id || 'markley';
|
|
9131
|
+
if (!engines[id]) {
|
|
9132
|
+
engines[id] = createLeeTetrahedralEngine(
|
|
9133
|
+
getProjectionRotation(id),
|
|
9134
|
+
id == 'markley' ? MARKLEY_LAYOUT_PHASE : CALM_LAYOUT_PHASE
|
|
9135
|
+
);
|
|
9136
|
+
}
|
|
9137
|
+
return engines[id];
|
|
9138
|
+
}
|
|
9139
|
+
|
|
9140
|
+
function initLeeTetrahedral(P, id) {
|
|
9141
|
+
var engine = getLeeTetrahedralEngine(id);
|
|
9142
|
+
P.es = 0;
|
|
9143
|
+
P.inv = null;
|
|
9144
|
+
P.fwd = function(lp, xy) {
|
|
9145
|
+
var p = engine.forward(lp.lam, lp.phi);
|
|
9146
|
+
xy.x = p[0];
|
|
9147
|
+
xy.y = p[1];
|
|
9148
|
+
};
|
|
9149
|
+
P.__projection_topology = engine.getTopology(P.lam0 * R2D$1);
|
|
9150
|
+
P.__projected_outline = engine.outline;
|
|
9151
|
+
P.__graticule_precision = 1;
|
|
9152
|
+
}
|
|
9153
|
+
|
|
9154
|
+
function getProjectionRotation(id) {
|
|
9155
|
+
if (id == 'calm') {
|
|
9156
|
+
// Kunimune's published CALM aspect (77°N, 143°E, central meridian
|
|
9157
|
+
// 163°W), transformed into this implementation's tetrahedral symmetry.
|
|
9158
|
+
return [
|
|
9159
|
+
64.7261399569101,
|
|
9160
|
+
-39.84470062116125,
|
|
9161
|
+
-119.02303523591051
|
|
9162
|
+
];
|
|
9163
|
+
}
|
|
9164
|
+
// Markley's singularities are at ±35.26439°, in the oceans.
|
|
9165
|
+
return [115, MARKLEY_LATITUDE - 90, 180];
|
|
9166
|
+
}
|
|
9167
|
+
|
|
9168
|
+
function createLeeTetrahedralEngine(rotation, layoutPhase) {
|
|
9169
|
+
var base = createPolyhedralProjection({
|
|
9170
|
+
faces: TETRAHEDRON_FACES,
|
|
9171
|
+
parents: [-1, 0, 0, 0],
|
|
9172
|
+
rotation: rotation,
|
|
9173
|
+
angle: 30,
|
|
9174
|
+
faceProjector: createLeeFaceProjector
|
|
9175
|
+
});
|
|
9176
|
+
var normalization = getBaseNormalization(base.outline);
|
|
9177
|
+
var baseTopology = base.getTopology(0);
|
|
9178
|
+
var sourceRegions = createSourceRegions(rotation);
|
|
9179
|
+
var rasterPieces = createLayoutPieces(
|
|
9180
|
+
baseTopology.regions, normalization, layoutPhase);
|
|
9181
|
+
var rasterPieceIndex = indexPiecesByFaceAndCopy(rasterPieces);
|
|
9182
|
+
var rasterPieceIds = rasterPieces.map(function(piece) { return piece.id; });
|
|
9183
|
+
var seamCache = new Map();
|
|
9184
|
+
var outline = [[
|
|
9185
|
+
centerOutputPoint([RECT_XMIN, RECT_YMIN]),
|
|
9186
|
+
centerOutputPoint([RECT_XMAX, RECT_YMIN]),
|
|
9187
|
+
centerOutputPoint([RECT_XMAX, RECT_YMAX]),
|
|
9188
|
+
centerOutputPoint([RECT_XMIN, RECT_YMAX]),
|
|
9189
|
+
centerOutputPoint([RECT_XMIN, RECT_YMIN])
|
|
9190
|
+
]];
|
|
9191
|
+
|
|
9192
|
+
return {
|
|
9193
|
+
forward: forward,
|
|
9194
|
+
inverse: inverse,
|
|
9195
|
+
outline: outline,
|
|
9196
|
+
getTopology: getTopology
|
|
9197
|
+
};
|
|
9198
|
+
|
|
9199
|
+
function forward(lam, phi) {
|
|
9200
|
+
var p = normalizeBasePoint(base.forward(lam, phi), normalization);
|
|
9201
|
+
var copy = getLayoutCopy(p);
|
|
9202
|
+
var q = applyMatrix(copy.matrix, p);
|
|
9203
|
+
q[0] = wrapLayoutX(q[0] + layoutPhase);
|
|
9204
|
+
q[0] = clamp$2(q[0], RECT_XMIN, RECT_XMAX);
|
|
9205
|
+
q[1] = clamp$2(q[1], RECT_YMIN, RECT_YMAX);
|
|
9206
|
+
return centerOutputPoint(q);
|
|
9207
|
+
}
|
|
9208
|
+
|
|
9209
|
+
// Internal inverse used to trace the geographic cut corresponding to the
|
|
9210
|
+
// rectangular frame. The public projection remains forward-only.
|
|
9211
|
+
function inverse(x, y) {
|
|
9212
|
+
var q = uncenterOutputPoint([x, y]);
|
|
9213
|
+
for (var i = 0; i < rasterPieces.length; i++) {
|
|
9214
|
+
var piece = rasterPieces[i];
|
|
9215
|
+
if (!pointInRing$2(centerOutputPoint(q), piece.boundary)) continue;
|
|
9216
|
+
var p = applyMatrix(invertMatrix(piece.matrix), q);
|
|
9217
|
+
var projected = getLayoutCopy(p);
|
|
9218
|
+
if (projected.id != piece.copy) continue;
|
|
9219
|
+
p = denormalizeBasePoint(p, normalization);
|
|
9220
|
+
var spherical = base.invertFace(p[0], p[1], piece.face);
|
|
9221
|
+
if (!spherical) continue;
|
|
9222
|
+
var check = forward(spherical[0], spherical[1]);
|
|
9223
|
+
if (Math.hypot(check[0] - x, check[1] - y) < 1e-6) {
|
|
9224
|
+
return spherical;
|
|
9225
|
+
}
|
|
9226
|
+
}
|
|
9227
|
+
return null;
|
|
9228
|
+
}
|
|
9229
|
+
|
|
9230
|
+
function getTopology(lon0) {
|
|
9231
|
+
var result = {
|
|
9232
|
+
interrupted: true,
|
|
9233
|
+
regions: rasterPieces.map(copyProjectedPiece),
|
|
9234
|
+
findRegion: findRegion,
|
|
9235
|
+
findTransitionRegion: findRegion,
|
|
9236
|
+
projectRegion: projectRegion,
|
|
9237
|
+
raster_regions: rasterPieces.map(copyRasterPiece),
|
|
9238
|
+
raster_source_regions: sourceRegions.map(function(region) {
|
|
9239
|
+
return {
|
|
9240
|
+
id: region.id,
|
|
9241
|
+
boundary: region.boundary.map(function(p) {
|
|
9242
|
+
return [
|
|
9243
|
+
normalizeLongitude$1(p[0] + lon0),
|
|
9244
|
+
p[1]
|
|
9245
|
+
];
|
|
9246
|
+
})
|
|
9247
|
+
};
|
|
9248
|
+
}),
|
|
9249
|
+
raster_mesh_interval: 32,
|
|
9250
|
+
raster_cell_halo: false,
|
|
9251
|
+
fill_raster_mask: true,
|
|
9252
|
+
fill_raster_coverage: true,
|
|
9253
|
+
findRasterRegion: findRasterRegion,
|
|
9254
|
+
projectRasterRegion: projectRasterRegion,
|
|
9255
|
+
projectRasterSourceRegion: projectRasterSourceRegion,
|
|
9256
|
+
clipRasterRegionPolygon: clipRasterRegionPolygon,
|
|
9257
|
+
frame_bounds: [
|
|
9258
|
+
outline[0][0][0],
|
|
9259
|
+
outline[0][0][1],
|
|
9260
|
+
outline[0][2][0],
|
|
9261
|
+
outline[0][2][1]
|
|
9262
|
+
],
|
|
9263
|
+
outline: outline.map(function(ring) {
|
|
9264
|
+
return ring.map(function(p) { return p.concat(); });
|
|
9265
|
+
})
|
|
9266
|
+
};
|
|
9267
|
+
// Rasters use the region mesh but never need geographic seam paths.
|
|
9268
|
+
// Tracing the rectangular cut is deferred until vector clipping requests it.
|
|
9269
|
+
Object.defineProperty(result, 'seams', {
|
|
9270
|
+
enumerable: true,
|
|
9271
|
+
get: function() {
|
|
9272
|
+
if (!seamCache.has(lon0)) {
|
|
9273
|
+
var topology = base.getTopology(lon0);
|
|
9274
|
+
var seams = topology.seams.map(function(seam) {
|
|
9275
|
+
return {
|
|
9276
|
+
type: 'attached',
|
|
9277
|
+
faces: seam.faces,
|
|
9278
|
+
paths: seam.paths
|
|
9279
|
+
};
|
|
9280
|
+
});
|
|
9281
|
+
seams.push({
|
|
9282
|
+
type: 'cut',
|
|
9283
|
+
paths: createFrameCutPaths(inverse, lon0)
|
|
9284
|
+
});
|
|
9285
|
+
seamCache.set(lon0, seams);
|
|
9286
|
+
}
|
|
9287
|
+
return seamCache.get(lon0);
|
|
9288
|
+
}
|
|
9289
|
+
});
|
|
9290
|
+
return result;
|
|
9291
|
+
|
|
9292
|
+
function findRegion(lon, lat) {
|
|
9293
|
+
var lam = normalizeLongitude$1(lon - lon0) * D2R$1;
|
|
9294
|
+
var phi = lat * D2R$1;
|
|
9295
|
+
var face = base.findFace(lam, phi);
|
|
9296
|
+
var p = normalizeBasePoint(base.forwardFace(lam, phi, face), normalization);
|
|
9297
|
+
var copy = getLayoutCopy(p);
|
|
9298
|
+
var q = applyMatrix(copy.matrix, p);
|
|
9299
|
+
q[0] = wrapLayoutX(q[0] + layoutPhase);
|
|
9300
|
+
q[0] = clamp$2(q[0], RECT_XMIN, RECT_XMAX);
|
|
9301
|
+
q[1] = clamp$2(q[1], RECT_YMIN, RECT_YMAX);
|
|
9302
|
+
q = centerOutputPoint(q);
|
|
9303
|
+
var ids = rasterPieceIndex.get(getPieceKey(face, copy.id)) || [];
|
|
9304
|
+
var region = findPieceContainingPoint(rasterPieces, ids, q);
|
|
9305
|
+
if (region === undefined) {
|
|
9306
|
+
region = findPieceContainingPoint(rasterPieces, rasterPieceIds, q);
|
|
9307
|
+
}
|
|
9308
|
+
return region;
|
|
9309
|
+
}
|
|
9310
|
+
|
|
9311
|
+
function projectRegion(lon, lat, regionId) {
|
|
9312
|
+
return projectPiece(lon, lat, rasterPieces[regionId]);
|
|
9313
|
+
}
|
|
9314
|
+
|
|
9315
|
+
function findRasterRegion(lon, lat) {
|
|
9316
|
+
return findRegion(lon, lat);
|
|
9317
|
+
}
|
|
9318
|
+
|
|
9319
|
+
function projectRasterRegion(lon, lat, regionId) {
|
|
9320
|
+
return projectPiece(lon, lat, rasterPieces[regionId]);
|
|
9321
|
+
}
|
|
9322
|
+
|
|
9323
|
+
function projectPiece(lon, lat, piece) {
|
|
9324
|
+
var lam = normalizeLongitude$1(lon - lon0) * D2R$1;
|
|
9325
|
+
var p = normalizeBasePoint(
|
|
9326
|
+
base.forwardFace(lam, lat * D2R$1, piece.face),
|
|
9327
|
+
normalization
|
|
9328
|
+
);
|
|
9329
|
+
return centerOutputPoint(applyMatrix(piece.matrix, p));
|
|
9330
|
+
}
|
|
9331
|
+
|
|
9332
|
+
function projectRasterSourceRegion(lon, lat, sourceRegionId) {
|
|
9333
|
+
var lam = normalizeLongitude$1(lon - lon0) * D2R$1;
|
|
9334
|
+
return normalizeBasePoint(
|
|
9335
|
+
base.forwardFace(lam, lat * D2R$1, sourceRegionId),
|
|
9336
|
+
normalization
|
|
9337
|
+
);
|
|
9338
|
+
}
|
|
9339
|
+
|
|
9340
|
+
function clipRasterRegionPolygon(vertices, regionId) {
|
|
9341
|
+
var piece = rasterPieces[regionId];
|
|
9342
|
+
var polygon = vertices.map(function(vertex) {
|
|
9343
|
+
var p = applyMatrix(piece.matrix, [vertex.x, vertex.y]);
|
|
9344
|
+
return copyRasterVertex(vertex, p[0], p[1]);
|
|
9345
|
+
});
|
|
9346
|
+
polygon = clipRasterPolygonAxis(polygon, 'x', RECT_XMIN, true);
|
|
9347
|
+
polygon = clipRasterPolygonAxis(polygon, 'x', RECT_XMAX, false);
|
|
9348
|
+
polygon = clipRasterPolygonAxis(polygon, 'y', RECT_YMIN, true);
|
|
9349
|
+
polygon = clipRasterPolygonAxis(polygon, 'y', RECT_YMAX, false);
|
|
9350
|
+
polygon.forEach(function(vertex) {
|
|
9351
|
+
var p = centerOutputPoint([vertex.x, vertex.y]);
|
|
9352
|
+
vertex.x = p[0];
|
|
9353
|
+
vertex.y = p[1];
|
|
9354
|
+
});
|
|
9355
|
+
return polygon;
|
|
9356
|
+
}
|
|
9357
|
+
}
|
|
9358
|
+
}
|
|
9359
|
+
|
|
9360
|
+
function createSourceRegions(rotation) {
|
|
9361
|
+
return TETRAHEDRON_FACES.map(function(face, id) {
|
|
9362
|
+
var boundary = face.map(function(p) {
|
|
9363
|
+
var q = rotateSphericalRadians(
|
|
9364
|
+
p[0] * D2R$1, p[1] * D2R$1, rotation, true);
|
|
9365
|
+
return [normalizeLongitude$1(q[0] * R2D$1), q[1] * R2D$1];
|
|
9366
|
+
});
|
|
9367
|
+
boundary.push(boundary[0].concat());
|
|
9368
|
+
return {id: id, boundary: boundary};
|
|
9369
|
+
});
|
|
9370
|
+
}
|
|
9371
|
+
|
|
9372
|
+
function createLayoutPieces(regions, normalization, layoutPhase) {
|
|
9373
|
+
var pieces = [];
|
|
9374
|
+
regions.forEach(function(region) {
|
|
9375
|
+
var boundary = region.projected_boundary.map(function(p) {
|
|
9376
|
+
return normalizeBasePoint(p, normalization);
|
|
9377
|
+
});
|
|
9378
|
+
LAYOUT_COPIES.forEach(function(copy) {
|
|
9379
|
+
var polygon = clipLayoutCopyDomain(boundary, copy.id);
|
|
9380
|
+
if (polygon.length < 3 ||
|
|
9381
|
+
Math.abs(getRingArea$2(polygon)) < MIN_PIECE_AREA) return;
|
|
9382
|
+
[-LAYOUT_PERIOD, 0, LAYOUT_PERIOD].forEach(function(wrap) {
|
|
9383
|
+
var matrix = shiftMatrixX(copy.matrix, layoutPhase + wrap);
|
|
9384
|
+
var projected = polygon.map(function(p) {
|
|
9385
|
+
return applyMatrix(matrix, p);
|
|
9386
|
+
});
|
|
9387
|
+
projected = clipPolygonAxis(projected, 0, RECT_XMIN, true);
|
|
9388
|
+
projected = clipPolygonAxis(projected, 0, RECT_XMAX, false);
|
|
9389
|
+
projected = clipPolygonAxis(projected, 1, RECT_YMIN, true);
|
|
9390
|
+
projected = clipPolygonAxis(projected, 1, RECT_YMAX, false);
|
|
9391
|
+
if (projected.length < 3 ||
|
|
9392
|
+
Math.abs(getRingArea$2(projected)) < MIN_PIECE_AREA) return;
|
|
9393
|
+
pieces.push({
|
|
9394
|
+
id: pieces.length,
|
|
9395
|
+
face: region.id,
|
|
9396
|
+
source_region: region.id,
|
|
9397
|
+
copy: copy.id,
|
|
9398
|
+
matrix: matrix,
|
|
9399
|
+
boundary: projected.map(centerOutputPoint)
|
|
9400
|
+
});
|
|
9401
|
+
});
|
|
9402
|
+
});
|
|
9403
|
+
});
|
|
9404
|
+
return pieces;
|
|
9405
|
+
}
|
|
9406
|
+
|
|
9407
|
+
function clipLayoutCopyDomain(polygon, copyId) {
|
|
9408
|
+
if (copyId == 0) { // green
|
|
9409
|
+
polygon = clipPolygonAxis(polygon, 1, 0, true);
|
|
9410
|
+
polygon = clipPolygonAxis(polygon, 0, 3, false);
|
|
9411
|
+
} else if (copyId == 2) { // blue
|
|
9412
|
+
polygon = clipPolygonAxis(polygon, 1, 0, true);
|
|
9413
|
+
polygon = clipPolygonAxis(polygon, 0, 3, true);
|
|
9414
|
+
} else if (copyId == 1) { // red
|
|
9415
|
+
polygon = clipPolygonAxis(polygon, 1, 0, false);
|
|
9416
|
+
polygon = clipPolygonAxis(polygon, 0, 1, false);
|
|
9417
|
+
} else { // orange
|
|
9418
|
+
polygon = clipPolygonAxis(polygon, 1, 0, false);
|
|
9419
|
+
polygon = clipPolygonAxis(polygon, 0, 1, true);
|
|
9420
|
+
}
|
|
9421
|
+
return polygon;
|
|
9422
|
+
}
|
|
9423
|
+
|
|
9424
|
+
function copyProjectedPiece(piece) {
|
|
9425
|
+
return {
|
|
9426
|
+
id: piece.id,
|
|
9427
|
+
source_region: piece.source_region,
|
|
9428
|
+
copy: piece.copy,
|
|
9429
|
+
projected_boundary: closeRing$1(piece.boundary)
|
|
9430
|
+
};
|
|
9431
|
+
}
|
|
9432
|
+
|
|
9433
|
+
function copyRasterPiece(piece) {
|
|
9434
|
+
return {
|
|
9435
|
+
id: piece.id,
|
|
9436
|
+
source_region: piece.source_region,
|
|
9437
|
+
projected_boundary: closeRing$1(piece.boundary)
|
|
9438
|
+
};
|
|
9439
|
+
}
|
|
9440
|
+
|
|
9441
|
+
function createFrameCutPaths(inverse, lon0) {
|
|
9442
|
+
// The repeated tetrahedral net is continuous inside the frame. Its only
|
|
9443
|
+
// geographic cuts are the three independent sides of the periodic rectangle.
|
|
9444
|
+
var n = 6000;
|
|
9445
|
+
// Stay far enough inside the frame to avoid browser-specific inverse
|
|
9446
|
+
// branches at the exact Lee face boundary.
|
|
9447
|
+
var epsilon = 5e-8;
|
|
9448
|
+
var xmin = centerOutputPoint([RECT_XMIN, 0])[0];
|
|
9449
|
+
var xmax = centerOutputPoint([RECT_XMAX, 0])[0];
|
|
9450
|
+
var ymin = centerOutputPoint([0, RECT_YMIN])[1];
|
|
9451
|
+
var ymax = centerOutputPoint([0, RECT_YMAX])[1];
|
|
9452
|
+
var edges = [
|
|
9453
|
+
[[xmin + epsilon, ymin], [xmin + epsilon, ymax]],
|
|
9454
|
+
[[xmin, ymax - epsilon], [xmax, ymax - epsilon]],
|
|
9455
|
+
[[xmin, ymin + epsilon], [xmax, ymin + epsilon]]
|
|
9456
|
+
];
|
|
9457
|
+
return edges.reduce(function(memo, edge) {
|
|
9458
|
+
var path = [];
|
|
9459
|
+
for (var i = 0; i <= n; i++) {
|
|
9460
|
+
var t = i / n;
|
|
9461
|
+
var x = edge[0][0] + (edge[1][0] - edge[0][0]) * t;
|
|
9462
|
+
var y = edge[0][1] + (edge[1][1] - edge[0][1]) * t;
|
|
9463
|
+
var p = inverse(x, y);
|
|
9464
|
+
if (!p) continue;
|
|
9465
|
+
path.push([
|
|
9466
|
+
normalizeLongitude$1(p[0] * R2D$1 + lon0),
|
|
9467
|
+
p[1] * R2D$1
|
|
9468
|
+
]);
|
|
9469
|
+
}
|
|
9470
|
+
return memo.concat(splitPathAtAntimeridian$1(path));
|
|
9471
|
+
}, []).map(function(path) {
|
|
9472
|
+
path.mask_width = 4e-5;
|
|
9473
|
+
return path;
|
|
9474
|
+
});
|
|
9475
|
+
}
|
|
9476
|
+
|
|
9477
|
+
function splitPathAtAntimeridian$1(path) {
|
|
9478
|
+
if (path.length < 2) return [];
|
|
9479
|
+
var paths = [];
|
|
9480
|
+
var part = [path[0]];
|
|
9481
|
+
for (var i = 1; i < path.length; i++) {
|
|
9482
|
+
var a = path[i - 1];
|
|
9483
|
+
var b = path[i];
|
|
9484
|
+
if (Math.abs(a[0] - b[0]) > 180) {
|
|
9485
|
+
var adjusted = b[0] + (b[0] < a[0] ? 360 : -360);
|
|
9486
|
+
var edge = a[0] < 0 ? -180 : 180;
|
|
9487
|
+
var t = (edge - a[0]) / (adjusted - a[0]);
|
|
9488
|
+
var lat = a[1] + (b[1] - a[1]) * t;
|
|
9489
|
+
part.push([edge, lat]);
|
|
9490
|
+
paths.push(part);
|
|
9491
|
+
part = [[-edge, lat], b];
|
|
9492
|
+
} else {
|
|
9493
|
+
part.push(b);
|
|
9494
|
+
}
|
|
9495
|
+
}
|
|
9496
|
+
if (part.length > 1) paths.push(part);
|
|
9497
|
+
return paths;
|
|
9498
|
+
}
|
|
9499
|
+
|
|
9500
|
+
function closeRing$1(ring) {
|
|
9501
|
+
var copy = ring.map(function(p) { return p.concat(); });
|
|
9502
|
+
if (copy.length && !pointsEqual$2(copy[0], copy[copy.length - 1])) {
|
|
9503
|
+
copy.push(copy[0].concat());
|
|
9504
|
+
}
|
|
9505
|
+
return copy;
|
|
9506
|
+
}
|
|
9507
|
+
|
|
9508
|
+
function getLayoutCopy(p) {
|
|
9509
|
+
// The four transformed triangular nets tile the frame. These two straight
|
|
9510
|
+
// cuts select the unique copy containing a point from the base net.
|
|
9511
|
+
if (p[1] >= 0) return p[0] > 3 ? LAYOUT_COPIES[2] : LAYOUT_COPIES[0];
|
|
9512
|
+
return p[0] > 1 ? LAYOUT_COPIES[3] : LAYOUT_COPIES[1];
|
|
9513
|
+
}
|
|
9514
|
+
|
|
9515
|
+
function centerOutputPoint(p) {
|
|
9516
|
+
return [
|
|
9517
|
+
p[0] - (RECT_XMIN + RECT_XMAX) / 2,
|
|
9518
|
+
p[1] - (RECT_YMIN + RECT_YMAX) / 2
|
|
9519
|
+
];
|
|
9520
|
+
}
|
|
9521
|
+
|
|
9522
|
+
function uncenterOutputPoint(p) {
|
|
9523
|
+
return [
|
|
9524
|
+
p[0] + (RECT_XMIN + RECT_XMAX) / 2,
|
|
9525
|
+
p[1] + (RECT_YMIN + RECT_YMAX) / 2
|
|
9526
|
+
];
|
|
9527
|
+
}
|
|
9528
|
+
|
|
9529
|
+
function getBaseNormalization(outline) {
|
|
9530
|
+
var xmin = Infinity;
|
|
9531
|
+
var ymin = Infinity;
|
|
9532
|
+
var xmax = -Infinity;
|
|
9533
|
+
var ymax = -Infinity;
|
|
9534
|
+
outline.forEach(function(ring) {
|
|
9535
|
+
ring.forEach(function(p) {
|
|
9536
|
+
xmin = Math.min(xmin, p[0]);
|
|
9537
|
+
ymin = Math.min(ymin, p[1]);
|
|
9538
|
+
xmax = Math.max(xmax, p[0]);
|
|
9539
|
+
ymax = Math.max(ymax, p[1]);
|
|
9540
|
+
});
|
|
9541
|
+
});
|
|
9542
|
+
return {
|
|
9543
|
+
cx: (xmin + xmax) / 2,
|
|
9544
|
+
cy: (ymin + ymax) / 2,
|
|
9545
|
+
scale: 8 / (xmax - xmin)
|
|
9546
|
+
};
|
|
9547
|
+
}
|
|
9548
|
+
|
|
9549
|
+
function normalizeBasePoint(p, normalization) {
|
|
9550
|
+
return [
|
|
9551
|
+
(p[0] - normalization.cx) * normalization.scale,
|
|
9552
|
+
-(p[1] - normalization.cy) * normalization.scale
|
|
9553
|
+
];
|
|
9554
|
+
}
|
|
9555
|
+
|
|
9556
|
+
function denormalizeBasePoint(p, normalization) {
|
|
9557
|
+
return [
|
|
9558
|
+
p[0] / normalization.scale + normalization.cx,
|
|
9559
|
+
-p[1] / normalization.scale + normalization.cy
|
|
9560
|
+
];
|
|
9561
|
+
}
|
|
9562
|
+
|
|
9563
|
+
function createLeeFaceProjector(face) {
|
|
9564
|
+
var c = face.centroid;
|
|
9565
|
+
var rotation = Math.abs(c[1]) == 90 ?
|
|
9566
|
+
[0, -c[1], -30] :
|
|
9567
|
+
[-c[0], -c[1], 30];
|
|
9568
|
+
function project(lam, phi) {
|
|
9569
|
+
var p = rotateSphericalRadians(lam, phi, rotation);
|
|
9570
|
+
var q = leeRaw(p[0], p[1]);
|
|
9571
|
+
return [q[0], -q[1]];
|
|
9572
|
+
}
|
|
9573
|
+
project.invert = function(x, y) {
|
|
9574
|
+
var p = invertLeeRaw(x, -y);
|
|
9575
|
+
return p && rotateSphericalRadians(p[0], p[1], rotation, true);
|
|
9576
|
+
};
|
|
9577
|
+
return project;
|
|
9578
|
+
}
|
|
9579
|
+
|
|
9580
|
+
function leeRaw(lam, phi) {
|
|
9581
|
+
var w = [-0.5, SQRT3 / 2];
|
|
9582
|
+
var z = complexMultiply(stereographicRaw(lam, phi), [SQRT2, 0]);
|
|
9583
|
+
var powers = [0, 1, 2].map(function(i) {
|
|
9584
|
+
return complexPower(w, [i, 0]);
|
|
9585
|
+
});
|
|
9586
|
+
var sector = 0;
|
|
9587
|
+
for (var i = 1; i < powers.length; i++) {
|
|
9588
|
+
if (complexMultiply(z, powers[i])[0] >
|
|
9589
|
+
complexMultiply(z, powers[sector])[0]) sector = i;
|
|
9590
|
+
}
|
|
9591
|
+
var rot = powers[sector];
|
|
9592
|
+
var n = complexNorm(z);
|
|
9593
|
+
var h = [0, 0];
|
|
9594
|
+
var k = [0, 0];
|
|
9595
|
+
|
|
9596
|
+
if (n > 0.3) {
|
|
9597
|
+
var y = complexSubtract([1, 0], complexMultiply(rot, z));
|
|
9598
|
+
var w1 = 1.4021821053254548;
|
|
9599
|
+
var coefficients = [
|
|
9600
|
+
1.15470053837925, 0.192450089729875, 0.0481125224324687,
|
|
9601
|
+
0.010309826235529, 3.34114739114366e-4, -0.00150351632601465,
|
|
9602
|
+
-0.0012304417796231, -675190201960282e-18,
|
|
9603
|
+
-284084537293856e-18, -821205120500051e-19,
|
|
9604
|
+
-159257630018706e-20, 1.91691805888369e-5,
|
|
9605
|
+
1.73095888028726e-5, 1.03865580818367e-5,
|
|
9606
|
+
4.70614523937179e-6, 1.4413500104181e-6,
|
|
9607
|
+
1.92757960170179e-8, -3.82869799649063e-7,
|
|
9608
|
+
-3.57526015225576e-7, -2.2175964844211e-7
|
|
9609
|
+
];
|
|
9610
|
+
var g = [0, 0];
|
|
9611
|
+
for (i = coefficients.length - 1; i >= 0; i--) {
|
|
9612
|
+
g = complexAdd([coefficients[i], 0], complexMultiply(g, y));
|
|
9613
|
+
}
|
|
9614
|
+
k = complexSubtract([w1, 0], complexMultiply(complexPower(y, 0.5), g));
|
|
9615
|
+
k = complexMultiply(complexMultiply(k, rot), rot);
|
|
9616
|
+
}
|
|
9617
|
+
|
|
9618
|
+
if (n < 0.5) {
|
|
9619
|
+
var h0 = [1, 1 / 8, 3 / 56, 1 / 32, 35 / 1664, 63 / 4096, 231 / 19456];
|
|
9620
|
+
var z3 = complexPower(z, [3, 0]);
|
|
9621
|
+
for (i = h0.length - 1; i >= 0; i--) {
|
|
9622
|
+
h = complexAdd([h0[i], 0], complexMultiply(h, z3));
|
|
9623
|
+
}
|
|
9624
|
+
h = complexMultiply(h, z);
|
|
9625
|
+
}
|
|
9626
|
+
|
|
9627
|
+
if (n < 0.3) return h;
|
|
9628
|
+
if (n > 0.5) return k;
|
|
9629
|
+
var t = (n - 0.3) / 0.2;
|
|
9630
|
+
return complexAdd(
|
|
9631
|
+
complexMultiply(k, [t, 0]),
|
|
9632
|
+
complexMultiply(h, [1 - t, 0])
|
|
9633
|
+
);
|
|
9634
|
+
}
|
|
9635
|
+
|
|
9636
|
+
function invertLeeRaw(x, y) {
|
|
9637
|
+
var lam = x;
|
|
9638
|
+
var phi = y * 0.5;
|
|
9639
|
+
var da = 0;
|
|
9640
|
+
var db = 0;
|
|
9641
|
+
var err2 = Infinity;
|
|
9642
|
+
var eps = 1e-12;
|
|
9643
|
+
for (var i = 0; i < 40; i++) {
|
|
9644
|
+
var q = leeRaw(lam, phi);
|
|
9645
|
+
var tx = q[0] - x;
|
|
9646
|
+
var ty = q[1] - y;
|
|
9647
|
+
if (Math.abs(tx) < eps && Math.abs(ty) < eps) break;
|
|
9648
|
+
var error = tx * tx + ty * ty;
|
|
9649
|
+
if (error > err2) {
|
|
9650
|
+
lam -= da /= 2;
|
|
9651
|
+
phi -= db /= 2;
|
|
9652
|
+
continue;
|
|
9653
|
+
}
|
|
9654
|
+
err2 = error;
|
|
9655
|
+
var ea = (lam > 0 ? -1 : 1) * eps;
|
|
9656
|
+
var eb = (phi > 0 ? -1 : 1) * eps;
|
|
9657
|
+
var qa = leeRaw(lam + ea, phi);
|
|
9658
|
+
var qb = leeRaw(lam, phi + eb);
|
|
9659
|
+
var dxa = (qa[0] - q[0]) / ea;
|
|
9660
|
+
var dya = (qa[1] - q[1]) / ea;
|
|
9661
|
+
var dxb = (qb[0] - q[0]) / eb;
|
|
9662
|
+
var dyb = (qb[1] - q[1]) / eb;
|
|
9663
|
+
var det = dyb * dxa - dya * dxb;
|
|
9664
|
+
if (Math.abs(det) < 1e-14) break;
|
|
9665
|
+
var scale = (Math.abs(det) < 0.5 ? 0.5 : 1) / det;
|
|
9666
|
+
da = (ty * dxb - tx * dyb) * scale;
|
|
9667
|
+
db = (tx * dya - ty * dxa) * scale;
|
|
9668
|
+
lam += da;
|
|
9669
|
+
phi += db;
|
|
9670
|
+
if (Math.abs(da) < eps && Math.abs(db) < eps) break;
|
|
9671
|
+
}
|
|
9672
|
+
var check = leeRaw(lam, phi);
|
|
9673
|
+
return Math.hypot(check[0] - x, check[1] - y) < 1e-8 ?
|
|
9674
|
+
[lam, phi] : null;
|
|
9675
|
+
}
|
|
9676
|
+
|
|
9677
|
+
function stereographicRaw(lam, phi) {
|
|
9678
|
+
var cosPhi = Math.cos(phi);
|
|
9679
|
+
var k = 1 / (1 + cosPhi * Math.cos(lam));
|
|
9680
|
+
return [k * cosPhi * Math.sin(lam), k * Math.sin(phi)];
|
|
9681
|
+
}
|
|
9682
|
+
|
|
9683
|
+
function complexAdd(a, b) {
|
|
9684
|
+
return [a[0] + b[0], a[1] + b[1]];
|
|
9685
|
+
}
|
|
9686
|
+
|
|
9687
|
+
function complexSubtract(a, b) {
|
|
9688
|
+
return [a[0] - b[0], a[1] - b[1]];
|
|
9689
|
+
}
|
|
9690
|
+
|
|
9691
|
+
function complexMultiply(a, b) {
|
|
9692
|
+
return [a[0] * b[0] - a[1] * b[1], a[1] * b[0] + a[0] * b[1]];
|
|
9693
|
+
}
|
|
9694
|
+
|
|
9695
|
+
function complexNorm(a) {
|
|
9696
|
+
return Math.hypot(a[0], a[1]);
|
|
9697
|
+
}
|
|
9698
|
+
|
|
9699
|
+
function complexPower(value, exponent) {
|
|
9700
|
+
var a = value[0];
|
|
9701
|
+
var b = value[1];
|
|
9702
|
+
var n = typeof exponent == 'number' ? [exponent, 0] : exponent;
|
|
9703
|
+
if (a === 0 && b === 0) return [0, 0];
|
|
9704
|
+
if (!n[1] && b === 0 && a >= 0) {
|
|
9705
|
+
return [Math.pow(a, n[0]), 0];
|
|
9706
|
+
}
|
|
9707
|
+
var arg = Math.atan2(b, a);
|
|
9708
|
+
var logNorm = Math.log(Math.hypot(a, b));
|
|
9709
|
+
var magnitude = Math.exp(n[0] * logNorm - n[1] * arg);
|
|
9710
|
+
var angle = n[1] * logNorm + n[0] * arg;
|
|
9711
|
+
return [magnitude * Math.cos(angle), magnitude * Math.sin(angle)];
|
|
9712
|
+
}
|
|
9713
|
+
|
|
9714
|
+
function applyMatrix(m, p) {
|
|
9715
|
+
return [
|
|
9716
|
+
m[0] * p[0] + m[1] * p[1] + m[2],
|
|
9717
|
+
m[3] * p[0] + m[4] * p[1] + m[5]
|
|
9718
|
+
];
|
|
9719
|
+
}
|
|
9720
|
+
|
|
9721
|
+
function shiftMatrixX(matrix, offset) {
|
|
9722
|
+
var shifted = matrix.concat();
|
|
9723
|
+
shifted[2] += offset;
|
|
9724
|
+
return shifted;
|
|
9725
|
+
}
|
|
9726
|
+
|
|
9727
|
+
function wrapLayoutX(x) {
|
|
9728
|
+
while (x < RECT_XMIN) x += LAYOUT_PERIOD;
|
|
9729
|
+
while (x > RECT_XMAX) x -= LAYOUT_PERIOD;
|
|
9730
|
+
return x;
|
|
9731
|
+
}
|
|
9732
|
+
|
|
9733
|
+
function invertMatrix(m) {
|
|
9734
|
+
var det = m[0] * m[4] - m[1] * m[3];
|
|
9735
|
+
return [
|
|
9736
|
+
m[4] / det,
|
|
9737
|
+
-m[1] / det,
|
|
9738
|
+
(m[1] * m[5] - m[4] * m[2]) / det,
|
|
9739
|
+
-m[3] / det,
|
|
9740
|
+
m[0] / det,
|
|
9741
|
+
(m[3] * m[2] - m[0] * m[5]) / det
|
|
9742
|
+
];
|
|
9743
|
+
}
|
|
9744
|
+
|
|
9745
|
+
function clipPolygonAxis(polygon, axis, value, keepGreater) {
|
|
9746
|
+
var output = [];
|
|
9747
|
+
if (!polygon.length) return output;
|
|
9748
|
+
var a = polygon[polygon.length - 1];
|
|
9749
|
+
var aInside = keepGreater ? a[axis] >= value - EPS : a[axis] <= value + EPS;
|
|
9750
|
+
polygon.forEach(function(b) {
|
|
9751
|
+
var bInside = keepGreater ? b[axis] >= value - EPS : b[axis] <= value + EPS;
|
|
9752
|
+
if (aInside != bInside) {
|
|
9753
|
+
var t = (value - a[axis]) / (b[axis] - a[axis]);
|
|
9754
|
+
var p = [
|
|
9755
|
+
a[0] + (b[0] - a[0]) * t,
|
|
9756
|
+
a[1] + (b[1] - a[1]) * t
|
|
9757
|
+
];
|
|
9758
|
+
p[axis] = value;
|
|
9759
|
+
output.push(p);
|
|
9760
|
+
}
|
|
9761
|
+
if (bInside) output.push(b.concat());
|
|
9762
|
+
a = b;
|
|
9763
|
+
aInside = bInside;
|
|
9764
|
+
});
|
|
9765
|
+
return output;
|
|
9766
|
+
}
|
|
9767
|
+
|
|
9768
|
+
function clipRasterPolygonAxis(polygon, axis, value, keepGreater) {
|
|
9769
|
+
var output = [];
|
|
9770
|
+
if (!polygon.length) return output;
|
|
9771
|
+
var a = polygon[polygon.length - 1];
|
|
9772
|
+
var aInside = keepGreater ? a[axis] >= value - EPS : a[axis] <= value + EPS;
|
|
9773
|
+
polygon.forEach(function(b) {
|
|
9774
|
+
var bInside = keepGreater ? b[axis] >= value - EPS : b[axis] <= value + EPS;
|
|
9775
|
+
if (aInside != bInside) {
|
|
9776
|
+
var t = (value - a[axis]) / (b[axis] - a[axis]);
|
|
9777
|
+
var vertex = {
|
|
9778
|
+
x: a.x + (b.x - a.x) * t,
|
|
9779
|
+
y: a.y + (b.y - a.y) * t,
|
|
9780
|
+
sx: a.sx + (b.sx - a.sx) * t,
|
|
9781
|
+
sy: a.sy + (b.sy - a.sy) * t,
|
|
9782
|
+
lon: interpolateLongitude(a.lon, b.lon, t),
|
|
9783
|
+
lat: a.lat + (b.lat - a.lat) * t
|
|
9784
|
+
};
|
|
9785
|
+
vertex[axis] = value;
|
|
9786
|
+
output.push(vertex);
|
|
9787
|
+
}
|
|
9788
|
+
if (bInside) output.push(copyRasterVertex(b, b.x, b.y));
|
|
9789
|
+
a = b;
|
|
9790
|
+
aInside = bInside;
|
|
9791
|
+
});
|
|
9792
|
+
return output;
|
|
9793
|
+
}
|
|
9794
|
+
|
|
9795
|
+
function copyRasterVertex(vertex, x, y) {
|
|
9796
|
+
return {
|
|
9797
|
+
x: x,
|
|
9798
|
+
y: y,
|
|
9799
|
+
sx: vertex.sx,
|
|
9800
|
+
sy: vertex.sy,
|
|
9801
|
+
lon: vertex.lon,
|
|
9802
|
+
lat: vertex.lat
|
|
9803
|
+
};
|
|
9804
|
+
}
|
|
9805
|
+
|
|
9806
|
+
function interpolateLongitude(a, b, t) {
|
|
9807
|
+
var delta = b - a;
|
|
9808
|
+
if (delta > 180) delta -= 360;
|
|
9809
|
+
if (delta < -180) delta += 360;
|
|
9810
|
+
return normalizeLongitude$1(a + delta * t);
|
|
9811
|
+
}
|
|
9812
|
+
|
|
9813
|
+
function getRingArea$2(ring) {
|
|
9814
|
+
var area = 0;
|
|
9815
|
+
for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
9816
|
+
area += ring[j][0] * ring[i][1] - ring[i][0] * ring[j][1];
|
|
9817
|
+
}
|
|
9818
|
+
return area / 2;
|
|
9819
|
+
}
|
|
9820
|
+
|
|
9821
|
+
function indexPiecesByFaceAndCopy(pieces) {
|
|
9822
|
+
var index = new Map();
|
|
9823
|
+
pieces.forEach(function(piece) {
|
|
9824
|
+
var key = getPieceKey(piece.face, piece.copy);
|
|
9825
|
+
if (!index.has(key)) index.set(key, []);
|
|
9826
|
+
index.get(key).push(piece.id);
|
|
9827
|
+
});
|
|
9828
|
+
return index;
|
|
9829
|
+
}
|
|
9830
|
+
|
|
9831
|
+
function findPieceContainingPoint(pieces, ids, point) {
|
|
9832
|
+
for (var i = 0; i < ids.length; i++) {
|
|
9833
|
+
if (pointInRing$2(point, pieces[ids[i]].boundary)) return ids[i];
|
|
9834
|
+
}
|
|
9835
|
+
}
|
|
9836
|
+
|
|
9837
|
+
function pointInRing$2(point, ring) {
|
|
9838
|
+
var inside = false;
|
|
9839
|
+
for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
9840
|
+
var a = ring[j];
|
|
9841
|
+
var b = ring[i];
|
|
9842
|
+
var cross = (point[0] - a[0]) * (b[1] - a[1]) -
|
|
9843
|
+
(point[1] - a[1]) * (b[0] - a[0]);
|
|
9844
|
+
if (Math.abs(cross) < 1e-8 &&
|
|
9845
|
+
point[0] >= Math.min(a[0], b[0]) - 1e-8 &&
|
|
9846
|
+
point[0] <= Math.max(a[0], b[0]) + 1e-8 &&
|
|
9847
|
+
point[1] >= Math.min(a[1], b[1]) - 1e-8 &&
|
|
9848
|
+
point[1] <= Math.max(a[1], b[1]) + 1e-8) return true;
|
|
9849
|
+
if ((a[1] > point[1]) != (b[1] > point[1]) &&
|
|
9850
|
+
point[0] < (b[0] - a[0]) * (point[1] - a[1]) /
|
|
9851
|
+
(b[1] - a[1]) + a[0]) {
|
|
9852
|
+
inside = !inside;
|
|
9853
|
+
}
|
|
9854
|
+
}
|
|
9855
|
+
return inside;
|
|
9856
|
+
}
|
|
9857
|
+
|
|
9858
|
+
function getPieceKey(face, copy) {
|
|
9859
|
+
return face + ':' + copy;
|
|
9860
|
+
}
|
|
9861
|
+
|
|
9862
|
+
function pointsEqual$2(a, b) {
|
|
9863
|
+
return Math.abs(a[0] - b[0]) < EPS && Math.abs(a[1] - b[1]) < EPS;
|
|
9864
|
+
}
|
|
9865
|
+
|
|
9866
|
+
function normalizeLongitude$1(lon) {
|
|
9867
|
+
lon = (lon + 180) % 360;
|
|
9868
|
+
if (lon < 0) lon += 360;
|
|
9869
|
+
return lon - 180;
|
|
9870
|
+
}
|
|
9871
|
+
|
|
9872
|
+
function clamp$2(value, min, max) {
|
|
9873
|
+
return Math.max(min, Math.min(max, value));
|
|
9874
|
+
}
|
|
9875
|
+
|
|
8541
9876
|
var mproj$1 = require$1('mproj');
|
|
8542
9877
|
registerDymaxionProjections(mproj$1);
|
|
8543
9878
|
registerButterflyProjections(mproj$1);
|
|
8544
9879
|
registerNarukawa2022Projection(mproj$1);
|
|
9880
|
+
registerLeeTetrahedralProjections(mproj$1);
|
|
8545
9881
|
|
|
8546
9882
|
var asyncLoader = null;
|
|
8547
9883
|
|
|
@@ -40961,10 +42297,10 @@ ${svg}
|
|
|
40961
42297
|
var coords = path.coords;
|
|
40962
42298
|
if (coords.length < 2) return;
|
|
40963
42299
|
if (forcePolylinePaths) {
|
|
40964
|
-
lines.push(path.closed || pointsEqual(coords[0], coords[coords.length - 1]) ? closeRing(coords) : coords);
|
|
42300
|
+
lines.push(path.closed || pointsEqual$1(coords[0], coords[coords.length - 1]) ? closeRing(coords) : coords);
|
|
40965
42301
|
return;
|
|
40966
42302
|
}
|
|
40967
|
-
if (path.closed || pointsEqual(coords[0], coords[coords.length - 1])) {
|
|
42303
|
+
if (path.closed || pointsEqual$1(coords[0], coords[coords.length - 1])) {
|
|
40968
42304
|
if (coords.length >= 3) {
|
|
40969
42305
|
rings.push(closeRing(coords));
|
|
40970
42306
|
}
|
|
@@ -41187,7 +42523,7 @@ ${svg}
|
|
|
41187
42523
|
for (var i = 0; i < subpaths.length; i++) {
|
|
41188
42524
|
var coords = subpaths[i].coords;
|
|
41189
42525
|
if (coords.length < 2) continue;
|
|
41190
|
-
if (!subpaths[i].closed && !pointsEqual(coords[0], coords[coords.length - 1])) {
|
|
42526
|
+
if (!subpaths[i].closed && !pointsEqual$1(coords[0], coords[coords.length - 1])) {
|
|
41191
42527
|
return true;
|
|
41192
42528
|
}
|
|
41193
42529
|
}
|
|
@@ -41272,7 +42608,7 @@ ${svg}
|
|
|
41272
42608
|
|
|
41273
42609
|
function closeRing(coords) {
|
|
41274
42610
|
var ring = coords.map(function(p) { return [p[0], p[1]]; });
|
|
41275
|
-
if (!pointsEqual(ring[0], ring[ring.length - 1])) {
|
|
42611
|
+
if (!pointsEqual$1(ring[0], ring[ring.length - 1])) {
|
|
41276
42612
|
ring.push([ring[0][0], ring[0][1]]);
|
|
41277
42613
|
}
|
|
41278
42614
|
return ring;
|
|
@@ -41327,7 +42663,7 @@ ${svg}
|
|
|
41327
42663
|
return /^[a-z]$/i.test(token);
|
|
41328
42664
|
}
|
|
41329
42665
|
|
|
41330
|
-
function pointsEqual(a, b) {
|
|
42666
|
+
function pointsEqual$1(a, b) {
|
|
41331
42667
|
return a && b && a[0] == b[0] && a[1] == b[1];
|
|
41332
42668
|
}
|
|
41333
42669
|
|
|
@@ -45620,7 +46956,7 @@ ${svg}
|
|
|
45620
46956
|
|
|
45621
46957
|
function stopIfBufferReachesPole(shape, dist) {
|
|
45622
46958
|
var maxAbsLat = 0;
|
|
45623
|
-
var angularDist = dist / R$3 * R2D$
|
|
46959
|
+
var angularDist = dist / R$3 * R2D$7;
|
|
45624
46960
|
(shape || []).forEach(function(path) {
|
|
45625
46961
|
latLngPathIter.init(path);
|
|
45626
46962
|
while (latLngPathIter.hasNext()) {
|
|
@@ -47737,12 +49073,12 @@ ${svg}
|
|
|
47737
49073
|
}
|
|
47738
49074
|
|
|
47739
49075
|
function projectBufferPoint(x, y, spherical) {
|
|
47740
|
-
return spherical ? [x * D2R$
|
|
49076
|
+
return spherical ? [x * D2R$8 * R$3, Math.log(Math.tan(Math.PI / 4 + y * D2R$8 / 2)) * R$3] :
|
|
47741
49077
|
[x, y];
|
|
47742
49078
|
}
|
|
47743
49079
|
|
|
47744
49080
|
function unprojectBufferPoint(x, y, spherical) {
|
|
47745
|
-
return spherical ? [x / (D2R$
|
|
49081
|
+
return spherical ? [x / (D2R$8 * R$3), (2 * Math.atan(Math.exp(y / R$3)) - Math.PI / 2) / (D2R$8)] :
|
|
47746
49082
|
[x, y];
|
|
47747
49083
|
}
|
|
47748
49084
|
|
|
@@ -52413,7 +53749,7 @@ ${svg}
|
|
|
52413
53749
|
var maxAbsLat = Math.max(Math.abs(bounds.ymin), Math.abs(bounds.ymax));
|
|
52414
53750
|
var maxPositiveDistance = getMaxPositiveBufferDistance(lyr, dataset, opts);
|
|
52415
53751
|
if (!(maxPositiveDistance > 0)) return false;
|
|
52416
|
-
return maxAbsLat + maxPositiveDistance / R$3 * R2D$
|
|
53752
|
+
return maxAbsLat + maxPositiveDistance / R$3 * R2D$7 >= 90 - POLAR_BUFFER_MARGIN_DEGREES;
|
|
52417
53753
|
}
|
|
52418
53754
|
|
|
52419
53755
|
function getMaxPositiveBufferDistance(lyr, dataset, opts) {
|
|
@@ -53665,7 +55001,7 @@ ${svg}
|
|
|
53665
55001
|
}
|
|
53666
55002
|
|
|
53667
55003
|
function getCoordinateDistance(distance, arcs) {
|
|
53668
|
-
return arcs.isPlanar() ? distance : distance / R$3 * R2D$
|
|
55004
|
+
return arcs.isPlanar() ? distance : distance / R$3 * R2D$7;
|
|
53669
55005
|
}
|
|
53670
55006
|
|
|
53671
55007
|
// @shapeIndex: chunk-bounds index of the source shape (see buildShapeSegmentIndex)
|
|
@@ -54334,7 +55670,7 @@ ${svg}
|
|
|
54334
55670
|
// depending on parameters
|
|
54335
55671
|
if (inList(P, 'cassini,gnom,bertin1953,chamb,ob_tran,tpeqd,healpix,rhealpix,' +
|
|
54336
55672
|
'ocea,omerc,tmerc,etmerc,nicol,dymaxion,dymaxion2,butterfly,butterfly2,' +
|
|
54337
|
-
'cahill_keyes,narukawa2022')) {
|
|
55673
|
+
'cahill_keyes,narukawa2022,markley,calm')) {
|
|
54338
55674
|
return false;
|
|
54339
55675
|
}
|
|
54340
55676
|
if (isAzimuthal(P)) {
|
|
@@ -54386,16 +55722,16 @@ ${svg}
|
|
|
54386
55722
|
}
|
|
54387
55723
|
|
|
54388
55724
|
function getRotationFunction2(rotation, inv) {
|
|
54389
|
-
var a = (rotation[0] || 0) * D2R$
|
|
54390
|
-
b = (rotation[1] || 0) * D2R$
|
|
54391
|
-
c = (rotation[2] || 0) * D2R$
|
|
55725
|
+
var a = (rotation[0] || 0) * D2R$8,
|
|
55726
|
+
b = (rotation[1] || 0) * D2R$8,
|
|
55727
|
+
c = (rotation[2] || 0) * D2R$8;
|
|
54392
55728
|
return function(p) {
|
|
54393
|
-
p[0] *= D2R$
|
|
54394
|
-
p[1] *= D2R$
|
|
55729
|
+
p[0] *= D2R$8;
|
|
55730
|
+
p[1] *= D2R$8;
|
|
54395
55731
|
var rotate = inv ? rotatePointInv : rotatePoint;
|
|
54396
55732
|
rotate(p, a, b, c);
|
|
54397
|
-
p[0] *= R2D$
|
|
54398
|
-
p[1] *= R2D$
|
|
55733
|
+
p[0] *= R2D$7;
|
|
55734
|
+
p[1] *= R2D$7;
|
|
54399
55735
|
return p;
|
|
54400
55736
|
};
|
|
54401
55737
|
}
|
|
@@ -54875,12 +56211,27 @@ ${svg}
|
|
|
54875
56211
|
type: o.type,
|
|
54876
56212
|
coordinates: rotatePath(o.coordinates, lon0)
|
|
54877
56213
|
};
|
|
54878
|
-
})
|
|
56214
|
+
}),
|
|
56215
|
+
findRegion: function(lon, lat) {
|
|
56216
|
+
return findClassicRegion(defn, normalizeLongitude(lon - lon0), lat);
|
|
56217
|
+
},
|
|
56218
|
+
findTransitionRegion: function(lon, lat) {
|
|
56219
|
+
return findClassicRegion(defn, normalizeLongitude(lon - lon0), lat);
|
|
56220
|
+
},
|
|
56221
|
+
constrainRegionPoint: function(lon, lat, regionId) {
|
|
56222
|
+
return constrainClassicRegionPoint(defn, lon0, lon, lat, regionId);
|
|
56223
|
+
},
|
|
56224
|
+
getRegionBoundary: function(regionId) {
|
|
56225
|
+
return getClassicRegionBoundary(defn, lon0, regionId, 0.5);
|
|
56226
|
+
}
|
|
54879
56227
|
};
|
|
54880
56228
|
}
|
|
54881
56229
|
|
|
54882
56230
|
function isInterruptedProjection(P) {
|
|
54883
56231
|
if (P && P.__projection_topology) {
|
|
56232
|
+
if (P.__projection_topology.interrupted !== undefined) {
|
|
56233
|
+
return P.__projection_topology.interrupted;
|
|
56234
|
+
}
|
|
54884
56235
|
return P.__projection_topology.seams.some(function(o) {
|
|
54885
56236
|
return o.type == 'cut';
|
|
54886
56237
|
});
|
|
@@ -54905,6 +56256,68 @@ ${svg}
|
|
|
54905
56256
|
};
|
|
54906
56257
|
}
|
|
54907
56258
|
|
|
56259
|
+
function findClassicRegion(defn, lon, lat) {
|
|
56260
|
+
for (var i = 0; i < defn.regions.length; i++) {
|
|
56261
|
+
var region = defn.regions[i];
|
|
56262
|
+
var ring = region.boundary;
|
|
56263
|
+
if (lon >= ring[0][0] && lon <= ring[2][0] &&
|
|
56264
|
+
lat >= ring[0][1] && lat <= ring[2][1]) {
|
|
56265
|
+
return region.id;
|
|
56266
|
+
}
|
|
56267
|
+
}
|
|
56268
|
+
return null;
|
|
56269
|
+
}
|
|
56270
|
+
|
|
56271
|
+
function constrainClassicRegionPoint(defn, lon0, lon, lat, regionId) {
|
|
56272
|
+
var region = findRegionById(defn, regionId);
|
|
56273
|
+
if (!region) return null;
|
|
56274
|
+
var ring = region.boundary;
|
|
56275
|
+
var xmin = ring[0][0];
|
|
56276
|
+
var ymin = ring[0][1];
|
|
56277
|
+
var xmax = ring[2][0];
|
|
56278
|
+
var ymax = ring[2][1];
|
|
56279
|
+
var localLon = normalizeLongitude(lon - lon0);
|
|
56280
|
+
var x = Math.max(xmin, Math.min(xmax, localLon));
|
|
56281
|
+
var y = Math.max(ymin, Math.min(ymax, lat));
|
|
56282
|
+
var cx = (xmin + xmax) / 2;
|
|
56283
|
+
var cy = (ymin + ymax) / 2;
|
|
56284
|
+
var inset = 1e-8;
|
|
56285
|
+
if (x == xmin || x == xmax) x += (cx - x) * inset;
|
|
56286
|
+
if (y == ymin || y == ymax) y += (cy - y) * inset;
|
|
56287
|
+
return [normalizeLongitude(x + lon0), y];
|
|
56288
|
+
}
|
|
56289
|
+
|
|
56290
|
+
function getClassicRegionBoundary(defn, lon0, regionId, interval) {
|
|
56291
|
+
var region = findRegionById(defn, regionId);
|
|
56292
|
+
if (!region) return null;
|
|
56293
|
+
var ring = region.boundary;
|
|
56294
|
+
var corners = [ring[0], ring[1], ring[2], ring[3], ring[0]];
|
|
56295
|
+
var points = [];
|
|
56296
|
+
for (var i = 1; i < corners.length; i++) {
|
|
56297
|
+
var a = corners[i - 1];
|
|
56298
|
+
var b = corners[i];
|
|
56299
|
+
var n = Math.max(1, Math.ceil(Math.max(
|
|
56300
|
+
Math.abs(b[0] - a[0]),
|
|
56301
|
+
Math.abs(b[1] - a[1])
|
|
56302
|
+
) / interval));
|
|
56303
|
+
for (var j = 0; j < n; j++) {
|
|
56304
|
+
points.push([
|
|
56305
|
+
normalizeLongitude(a[0] + (b[0] - a[0]) * j / n + lon0),
|
|
56306
|
+
a[1] + (b[1] - a[1]) * j / n
|
|
56307
|
+
]);
|
|
56308
|
+
}
|
|
56309
|
+
}
|
|
56310
|
+
points.push(points[0].concat());
|
|
56311
|
+
return points;
|
|
56312
|
+
}
|
|
56313
|
+
|
|
56314
|
+
function findRegionById(defn, regionId) {
|
|
56315
|
+
for (var i = 0; i < defn.regions.length; i++) {
|
|
56316
|
+
if (defn.regions[i].id == regionId) return defn.regions[i];
|
|
56317
|
+
}
|
|
56318
|
+
return null;
|
|
56319
|
+
}
|
|
56320
|
+
|
|
54908
56321
|
function cutSeam(coordinates) {
|
|
54909
56322
|
return {
|
|
54910
56323
|
type: 'cut',
|
|
@@ -55611,6 +57024,13 @@ ${svg}
|
|
|
55611
57024
|
|
|
55612
57025
|
var DEFAULT_MESH_INTERVAL = 32;
|
|
55613
57026
|
var DEFAULT_MAX_EDGE_FACTOR = 20;
|
|
57027
|
+
var DEFAULT_TOPOLOGY_MIN_CELL_SIZE = 0.5;
|
|
57028
|
+
var MAX_TOPOLOGY_SUBDIVISION_DEPTH = 12;
|
|
57029
|
+
var TOPOLOGY_SAMPLE_STEPS = 4;
|
|
57030
|
+
var TOPOLOGY_VERTEX_INSET = 1e-7;
|
|
57031
|
+
var PIECE_SAMPLE_STEPS = 4;
|
|
57032
|
+
var EXPANDED_FACET_MAX_EDGE_DEGREES = 2;
|
|
57033
|
+
var EXPANDED_FACET_MAX_CLIP_ERROR = 0.02;
|
|
55614
57034
|
|
|
55615
57035
|
function projectRasterGridForward(raster, srcCRS, destCRS, optsArg) {
|
|
55616
57036
|
var opts = optsArg || {};
|
|
@@ -55621,8 +57041,8 @@ ${svg}
|
|
|
55621
57041
|
var mesh, bbox, outSize, outGrid;
|
|
55622
57042
|
validateRasterGridForProjection(grid);
|
|
55623
57043
|
timeStart(timing, 'mesh');
|
|
55624
|
-
mesh =
|
|
55625
|
-
|
|
57044
|
+
mesh = buildRasterProjectionMesh(grid, srcCRS, destCRS, transform, interval, opts);
|
|
57045
|
+
classifyRasterMesh(mesh, opts);
|
|
55626
57046
|
timeEnd(timing, 'mesh');
|
|
55627
57047
|
bbox = opts.output_bbox || opts.outputBbox || getProjectedMeshBBox(mesh);
|
|
55628
57048
|
if (!bbox) stop$1('Unable to project raster layer');
|
|
@@ -55630,12 +57050,17 @@ ${svg}
|
|
|
55630
57050
|
outGrid = createProjectedRasterGrid(grid, raster, bbox, outSize.width, outSize.height, opts);
|
|
55631
57051
|
timeStart(timing, 'rasterize');
|
|
55632
57052
|
rasterizeProjectedMesh(grid, outGrid, mesh, getRasterProjectionSampleMethod(raster, opts));
|
|
57053
|
+
if (mesh.fillOutputCoverage) {
|
|
57054
|
+
fillProjectedRasterCoverage(outGrid);
|
|
57055
|
+
} else {
|
|
57056
|
+
fillIsolatedProjectedRasterHoles(outGrid);
|
|
57057
|
+
}
|
|
55633
57058
|
timeEnd(timing, 'rasterize');
|
|
55634
57059
|
if (timing) {
|
|
55635
57060
|
timing.outputWidth = outGrid.width;
|
|
55636
57061
|
timing.outputHeight = outGrid.height;
|
|
55637
57062
|
timing.meshVertices = mesh.vertices.length;
|
|
55638
|
-
timing.meshCells = mesh.cells.length;
|
|
57063
|
+
timing.meshCells = mesh.triangles ? mesh.triangles.length : mesh.cells.length;
|
|
55639
57064
|
timing.meshSkippedCells = mesh.skippedCellCount;
|
|
55640
57065
|
}
|
|
55641
57066
|
return outGrid;
|
|
@@ -55672,17 +57097,34 @@ ${svg}
|
|
|
55672
57097
|
var transform = getProjTransform2(srcCRS, destCRS);
|
|
55673
57098
|
var mesh, bbox;
|
|
55674
57099
|
validateRasterGridForProjection(grid);
|
|
55675
|
-
mesh =
|
|
55676
|
-
|
|
57100
|
+
mesh = buildRasterProjectionMesh(grid, srcCRS, destCRS, transform, interval, opts);
|
|
57101
|
+
classifyRasterMesh(mesh, opts);
|
|
55677
57102
|
bbox = getProjectedMeshBBox(mesh);
|
|
55678
57103
|
return bbox;
|
|
55679
57104
|
}
|
|
55680
57105
|
|
|
55681
57106
|
function getProjectedRasterMeshBBox(mesh, optsArg) {
|
|
55682
|
-
|
|
57107
|
+
classifyRasterMesh(mesh, optsArg || {});
|
|
55683
57108
|
return getProjectedMeshBBox(mesh);
|
|
55684
57109
|
}
|
|
55685
57110
|
|
|
57111
|
+
function buildRasterProjectionMesh(grid, srcCRS, destCRS, transform, interval, opts) {
|
|
57112
|
+
var topology = getProjectionTopology(destCRS);
|
|
57113
|
+
if (topology && (topology.raster_source_regions ||
|
|
57114
|
+
topology.raster_spherical_regions)) {
|
|
57115
|
+
return buildExpandedFacetRasterMesh(
|
|
57116
|
+
grid, srcCRS, destCRS, interval, topology);
|
|
57117
|
+
}
|
|
57118
|
+
if (topology && (topology.projectRasterRegion ||
|
|
57119
|
+
topology.projectRegion || topology.constrainRegionPoint)) {
|
|
57120
|
+
return buildPiecewiseProjectedRasterMesh(grid, srcCRS, destCRS, interval, topology);
|
|
57121
|
+
}
|
|
57122
|
+
if (topology && (topology.findTransitionRegion || topology.findRegion)) {
|
|
57123
|
+
return buildTopologyAwareProjectedRasterMesh(grid, srcCRS, destCRS, interval, opts);
|
|
57124
|
+
}
|
|
57125
|
+
return buildProjectedRasterMesh(grid, transform, interval);
|
|
57126
|
+
}
|
|
57127
|
+
|
|
55686
57128
|
function buildProjectedRasterMesh(grid, transform, interval) {
|
|
55687
57129
|
var xs = getMeshStops(grid.width, interval);
|
|
55688
57130
|
var ys = getMeshStops(grid.height, interval);
|
|
@@ -55699,6 +57141,494 @@ ${svg}
|
|
|
55699
57141
|
};
|
|
55700
57142
|
}
|
|
55701
57143
|
|
|
57144
|
+
function buildPiecewiseProjectedRasterMesh(grid, srcCRS, destCRS, interval, topology) {
|
|
57145
|
+
var wgs84 = parseCrsString$1('wgs84');
|
|
57146
|
+
var toGeographic = getProjTransform2(srcCRS, wgs84);
|
|
57147
|
+
var fromGeographic = getProjTransform2(wgs84, srcCRS);
|
|
57148
|
+
var toDestination = getProjTransform2(wgs84, destCRS);
|
|
57149
|
+
interval = Math.min(interval, topology.raster_mesh_interval || interval);
|
|
57150
|
+
var xs = getMeshStops(grid.width, interval);
|
|
57151
|
+
var ys = getMeshStops(grid.height, interval);
|
|
57152
|
+
var regions = topology.raster_regions || topology.regions;
|
|
57153
|
+
var mesh = {
|
|
57154
|
+
xs: xs,
|
|
57155
|
+
ys: ys,
|
|
57156
|
+
vertices: [],
|
|
57157
|
+
cells: [],
|
|
57158
|
+
topologyAware: true,
|
|
57159
|
+
subdivisionSkippedCellCount: 0,
|
|
57160
|
+
fillRegionMask: topology.fill_raster_mask,
|
|
57161
|
+
fillOutputCoverage: topology.fill_raster_coverage,
|
|
57162
|
+
projectedRegions: getProjectedRasterRegions(
|
|
57163
|
+
topology, regions, destCRS, toDestination)
|
|
57164
|
+
};
|
|
57165
|
+
var context = {
|
|
57166
|
+
grid: grid,
|
|
57167
|
+
topology: topology,
|
|
57168
|
+
destCRS: destCRS,
|
|
57169
|
+
toGeographic: toGeographic,
|
|
57170
|
+
fromGeographic: fromGeographic,
|
|
57171
|
+
toDestination: toDestination,
|
|
57172
|
+
findRegion: topology.findRasterRegion || topology.findRegion,
|
|
57173
|
+
projectRegion: topology.projectRasterRegion || topology.projectRegion,
|
|
57174
|
+
pieceHalo: topology.raster_cell_halo === false ? 0 : interval,
|
|
57175
|
+
mesh: mesh
|
|
57176
|
+
};
|
|
57177
|
+
for (var y = 0; y < ys.length - 1; y++) {
|
|
57178
|
+
for (var x = 0; x < xs.length - 1; x++) {
|
|
57179
|
+
appendPiecewiseMeshCells(context, xs[x], ys[y], xs[x + 1], ys[y + 1]);
|
|
57180
|
+
}
|
|
57181
|
+
}
|
|
57182
|
+
return mesh;
|
|
57183
|
+
}
|
|
57184
|
+
|
|
57185
|
+
function buildExpandedFacetRasterMesh(grid, srcCRS, destCRS, interval, topology) {
|
|
57186
|
+
var wgs84 = parseCrsString$1('wgs84');
|
|
57187
|
+
var fromGeographic = getProjTransform2(wgs84, srcCRS);
|
|
57188
|
+
var regions = topology.raster_regions;
|
|
57189
|
+
var mesh = {
|
|
57190
|
+
vertices: [],
|
|
57191
|
+
cells: [],
|
|
57192
|
+
triangles: [],
|
|
57193
|
+
topologyAware: true,
|
|
57194
|
+
subdivisionSkippedCellCount: 0,
|
|
57195
|
+
fillRegionMask: topology.fill_raster_mask,
|
|
57196
|
+
fillOutputCoverage: topology.fill_raster_coverage,
|
|
57197
|
+
projectedRegions: getProjectedRasterRegions(
|
|
57198
|
+
topology, regions, destCRS, getProjTransform2(wgs84, destCRS)),
|
|
57199
|
+
sourceWrapX: isLatLngCRS(srcCRS) &&
|
|
57200
|
+
Math.abs(grid.bbox[2] - grid.bbox[0] - 360) < 1e-3
|
|
57201
|
+
};
|
|
57202
|
+
var sourceRegions = topology.raster_source_regions ||
|
|
57203
|
+
topology.raster_spherical_regions;
|
|
57204
|
+
var piecesBySourceRegion = new Map();
|
|
57205
|
+
regions.forEach(function(region) {
|
|
57206
|
+
var key = getRasterSourceRegionKey(region);
|
|
57207
|
+
var pieces = piecesBySourceRegion.get(key) || [];
|
|
57208
|
+
pieces.push(region);
|
|
57209
|
+
piecesBySourceRegion.set(key, pieces);
|
|
57210
|
+
});
|
|
57211
|
+
var context = {
|
|
57212
|
+
grid: grid,
|
|
57213
|
+
topology: topology,
|
|
57214
|
+
destCRS: destCRS,
|
|
57215
|
+
fromGeographic: fromGeographic,
|
|
57216
|
+
mesh: mesh
|
|
57217
|
+
};
|
|
57218
|
+
sourceRegions.forEach(function(region) {
|
|
57219
|
+
var boundary = region.boundary;
|
|
57220
|
+
var pieces = piecesBySourceRegion.get(getRasterSourceRegionKey(region));
|
|
57221
|
+
var triangles = [];
|
|
57222
|
+
var end = pointsEqual2D(boundary[0], boundary[boundary.length - 1]) ?
|
|
57223
|
+
boundary.length - 1 : boundary.length;
|
|
57224
|
+
for (var i = 1; i < end - 1; i++) {
|
|
57225
|
+
triangles.push([boundary[0], boundary[i], boundary[i + 1]]);
|
|
57226
|
+
}
|
|
57227
|
+
triangles.forEach(function(triangle) {
|
|
57228
|
+
var depth = getSphericalTriangleSubdivisionDepth(
|
|
57229
|
+
triangle, EXPANDED_FACET_MAX_EDGE_DEGREES);
|
|
57230
|
+
subdivideSphericalRasterTriangle(
|
|
57231
|
+
context, triangle, region, pieces, depth);
|
|
57232
|
+
});
|
|
57233
|
+
});
|
|
57234
|
+
return mesh;
|
|
57235
|
+
}
|
|
57236
|
+
|
|
57237
|
+
function getRasterSourceRegionKey(region) {
|
|
57238
|
+
if (region.source_region != null) return String(region.source_region);
|
|
57239
|
+
if (region.facet != null && region.sector != null) {
|
|
57240
|
+
return region.facet + ':' + region.sector;
|
|
57241
|
+
}
|
|
57242
|
+
return String(region.id);
|
|
57243
|
+
}
|
|
57244
|
+
|
|
57245
|
+
function pointsEqual2D(a, b) {
|
|
57246
|
+
return a && b && Math.abs(a[0] - b[0]) < 1e-10 &&
|
|
57247
|
+
Math.abs(a[1] - b[1]) < 1e-10;
|
|
57248
|
+
}
|
|
57249
|
+
|
|
57250
|
+
function getSphericalTriangleSubdivisionDepth(triangle, maxDegrees) {
|
|
57251
|
+
var max = Math.max(
|
|
57252
|
+
sphericalPointDistance(triangle[0], triangle[1]),
|
|
57253
|
+
sphericalPointDistance(triangle[1], triangle[2]),
|
|
57254
|
+
sphericalPointDistance(triangle[2], triangle[0])
|
|
57255
|
+
);
|
|
57256
|
+
return Math.max(0, Math.ceil(Math.log(max / maxDegrees) / Math.LN2));
|
|
57257
|
+
}
|
|
57258
|
+
|
|
57259
|
+
function subdivideSphericalRasterTriangle(context, triangle, region, pieces, depth) {
|
|
57260
|
+
if (depth > 0) {
|
|
57261
|
+
var ab = sphericalPointMidpoint(triangle[0], triangle[1]);
|
|
57262
|
+
var bc = sphericalPointMidpoint(triangle[1], triangle[2]);
|
|
57263
|
+
var ca = sphericalPointMidpoint(triangle[2], triangle[0]);
|
|
57264
|
+
subdivideSphericalRasterTriangle(
|
|
57265
|
+
context, [triangle[0], ab, ca], region, pieces, depth - 1);
|
|
57266
|
+
subdivideSphericalRasterTriangle(
|
|
57267
|
+
context, [ab, triangle[1], bc], region, pieces, depth - 1);
|
|
57268
|
+
subdivideSphericalRasterTriangle(
|
|
57269
|
+
context, [ca, bc, triangle[2]], region, pieces, depth - 1);
|
|
57270
|
+
subdivideSphericalRasterTriangle(
|
|
57271
|
+
context, [ab, bc, ca], region, pieces, depth - 1);
|
|
57272
|
+
return;
|
|
57273
|
+
}
|
|
57274
|
+
var rawVertices = triangle.map(function(lonlat) {
|
|
57275
|
+
return projectSphericalRawVertex(context, lonlat, region);
|
|
57276
|
+
});
|
|
57277
|
+
normalizeWrappedTrianglePixels(
|
|
57278
|
+
rawVertices, context.grid.width, context.mesh.sourceWrapX);
|
|
57279
|
+
pieces.forEach(function(piece) {
|
|
57280
|
+
var polygon = context.topology.clipRasterRegionPolygon(
|
|
57281
|
+
rawVertices, piece.id);
|
|
57282
|
+
if (!rasterPiecePolygonIsAccurate(
|
|
57283
|
+
context.topology, polygon, piece.id)) return;
|
|
57284
|
+
polygon.forEach(function(vertex) {
|
|
57285
|
+
var p = scaleRawProjectionPoint(
|
|
57286
|
+
context.destCRS, [vertex.x, vertex.y]);
|
|
57287
|
+
vertex.x = p[0];
|
|
57288
|
+
vertex.y = p[1];
|
|
57289
|
+
});
|
|
57290
|
+
for (var i = 1; i < polygon.length - 1; i++) {
|
|
57291
|
+
var vertices = [polygon[0], polygon[i], polygon[i + 1]];
|
|
57292
|
+
context.mesh.vertices.push(vertices[0], vertices[1], vertices[2]);
|
|
57293
|
+
context.mesh.triangles.push({
|
|
57294
|
+
a: vertices[0],
|
|
57295
|
+
b: vertices[1],
|
|
57296
|
+
c: vertices[2],
|
|
57297
|
+
region: piece.id,
|
|
57298
|
+
valid: vertices.every(vertexIsValid)
|
|
57299
|
+
});
|
|
57300
|
+
}
|
|
57301
|
+
});
|
|
57302
|
+
}
|
|
57303
|
+
|
|
57304
|
+
function projectSphericalRawVertex(context, lonlat, region) {
|
|
57305
|
+
var sourceXY = context.fromGeographic(lonlat[0], lonlat[1]);
|
|
57306
|
+
var sourcePixel = sourceXY &&
|
|
57307
|
+
rasterMapXYToPixel(context.grid, sourceXY[0], sourceXY[1]);
|
|
57308
|
+
var p = context.topology.projectRasterSourceRegion ?
|
|
57309
|
+
context.topology.projectRasterSourceRegion(
|
|
57310
|
+
lonlat[0], lonlat[1], region.id) :
|
|
57311
|
+
context.topology.projectRasterSector(
|
|
57312
|
+
lonlat[0], lonlat[1], region.facet, region.sector);
|
|
57313
|
+
return {
|
|
57314
|
+
sx: sourcePixel ? sourcePixel[0] : NaN,
|
|
57315
|
+
sy: sourcePixel ? sourcePixel[1] : NaN,
|
|
57316
|
+
x: p && isFinite(p[0]) ? p[0] : NaN,
|
|
57317
|
+
y: p && isFinite(p[1]) ? p[1] : NaN,
|
|
57318
|
+
lon: lonlat[0],
|
|
57319
|
+
lat: lonlat[1]
|
|
57320
|
+
};
|
|
57321
|
+
}
|
|
57322
|
+
|
|
57323
|
+
function rasterPiecePolygonIsAccurate(topology, polygon, regionId) {
|
|
57324
|
+
// A triangle that crosses a forced sector discontinuity can yield invalid
|
|
57325
|
+
// interpolated clip vertices. Adjacent triangles cover the rejected sliver.
|
|
57326
|
+
return polygon.every(function(vertex) {
|
|
57327
|
+
var p = topology.projectRasterRegion(
|
|
57328
|
+
vertex.lon, vertex.lat, regionId);
|
|
57329
|
+
return p && Math.hypot(vertex.x - p[0], vertex.y - p[1]) <
|
|
57330
|
+
EXPANDED_FACET_MAX_CLIP_ERROR;
|
|
57331
|
+
});
|
|
57332
|
+
}
|
|
57333
|
+
|
|
57334
|
+
function normalizeWrappedTrianglePixels(vertices, width, wrap) {
|
|
57335
|
+
if (!wrap) return;
|
|
57336
|
+
var xmin = Math.min(vertices[0].sx, vertices[1].sx, vertices[2].sx);
|
|
57337
|
+
var xmax = Math.max(vertices[0].sx, vertices[1].sx, vertices[2].sx);
|
|
57338
|
+
if (xmax - xmin <= width / 2) return;
|
|
57339
|
+
vertices.forEach(function(vertex) {
|
|
57340
|
+
if (vertex.sx < width / 2) vertex.sx += width;
|
|
57341
|
+
});
|
|
57342
|
+
}
|
|
57343
|
+
|
|
57344
|
+
function sphericalPointMidpoint(a, b) {
|
|
57345
|
+
var av = lonLatToVector(a);
|
|
57346
|
+
var bv = lonLatToVector(b);
|
|
57347
|
+
return vectorToLonLat(normalizeVector3([
|
|
57348
|
+
av[0] + bv[0],
|
|
57349
|
+
av[1] + bv[1],
|
|
57350
|
+
av[2] + bv[2]
|
|
57351
|
+
]));
|
|
57352
|
+
}
|
|
57353
|
+
|
|
57354
|
+
function sphericalPointDistance(a, b) {
|
|
57355
|
+
var av = lonLatToVector(a);
|
|
57356
|
+
var bv = lonLatToVector(b);
|
|
57357
|
+
return Math.acos(clamp$1(
|
|
57358
|
+
av[0] * bv[0] + av[1] * bv[1] + av[2] * bv[2], -1, 1
|
|
57359
|
+
)) * 180 / Math.PI;
|
|
57360
|
+
}
|
|
57361
|
+
|
|
57362
|
+
function lonLatToVector(p) {
|
|
57363
|
+
var lam = p[0] * Math.PI / 180;
|
|
57364
|
+
var phi = p[1] * Math.PI / 180;
|
|
57365
|
+
var cosPhi = Math.cos(phi);
|
|
57366
|
+
return [Math.cos(lam) * cosPhi, Math.sin(lam) * cosPhi, Math.sin(phi)];
|
|
57367
|
+
}
|
|
57368
|
+
|
|
57369
|
+
function vectorToLonLat(p) {
|
|
57370
|
+
return [
|
|
57371
|
+
Math.atan2(p[1], p[0]) * 180 / Math.PI,
|
|
57372
|
+
Math.asin(clamp$1(p[2], -1, 1)) * 180 / Math.PI
|
|
57373
|
+
];
|
|
57374
|
+
}
|
|
57375
|
+
|
|
57376
|
+
function normalizeVector3(p) {
|
|
57377
|
+
var k = 1 / Math.hypot(p[0], p[1], p[2]);
|
|
57378
|
+
return [p[0] * k, p[1] * k, p[2] * k];
|
|
57379
|
+
}
|
|
57380
|
+
|
|
57381
|
+
function appendPiecewiseMeshCells(context, x0, y0, x1, y1) {
|
|
57382
|
+
getPieceRegionsInCell(context, x0, y0, x1, y1).forEach(function(regionId) {
|
|
57383
|
+
var v00 = projectPiecewiseMeshVertex(context, x0, y0, regionId);
|
|
57384
|
+
var v10 = projectPiecewiseMeshVertex(context, x1, y0, regionId);
|
|
57385
|
+
var v01 = projectPiecewiseMeshVertex(context, x0, y1, regionId);
|
|
57386
|
+
var v11 = projectPiecewiseMeshVertex(context, x1, y1, regionId);
|
|
57387
|
+
var cell = {
|
|
57388
|
+
v00: v00,
|
|
57389
|
+
v10: v10,
|
|
57390
|
+
v01: v01,
|
|
57391
|
+
v11: v11,
|
|
57392
|
+
region: regionId,
|
|
57393
|
+
valid: vertexIsValid(v00) && vertexIsValid(v10) &&
|
|
57394
|
+
vertexIsValid(v01) && vertexIsValid(v11)
|
|
57395
|
+
};
|
|
57396
|
+
context.mesh.vertices.push(v00, v10, v01, v11);
|
|
57397
|
+
context.mesh.cells.push(cell);
|
|
57398
|
+
});
|
|
57399
|
+
}
|
|
57400
|
+
|
|
57401
|
+
function getPieceRegionsInCell(context, x0, y0, x1, y1) {
|
|
57402
|
+
var ids = [];
|
|
57403
|
+
var halo = context.pieceHalo;
|
|
57404
|
+
samplePieceRegions(context, ids, x0, y0, x1, y1);
|
|
57405
|
+
if (halo > 0) {
|
|
57406
|
+
samplePieceRegions(
|
|
57407
|
+
context,
|
|
57408
|
+
ids,
|
|
57409
|
+
Math.max(0, x0 - halo),
|
|
57410
|
+
Math.max(0, y0 - halo),
|
|
57411
|
+
Math.min(context.grid.width, x1 + halo),
|
|
57412
|
+
Math.min(context.grid.height, y1 + halo)
|
|
57413
|
+
);
|
|
57414
|
+
}
|
|
57415
|
+
return ids;
|
|
57416
|
+
}
|
|
57417
|
+
|
|
57418
|
+
function samplePieceRegions(context, ids, x0, y0, x1, y1) {
|
|
57419
|
+
for (var iy = 0; iy <= PIECE_SAMPLE_STEPS; iy++) {
|
|
57420
|
+
for (var ix = 0; ix <= PIECE_SAMPLE_STEPS; ix++) {
|
|
57421
|
+
var px = x0 + (x1 - x0) * ix / PIECE_SAMPLE_STEPS;
|
|
57422
|
+
var py = y0 + (y1 - y0) * iy / PIECE_SAMPLE_STEPS;
|
|
57423
|
+
var xy = rasterPixelToMapXY(context.grid, px, py);
|
|
57424
|
+
var lonlat = context.toGeographic(xy[0], xy[1]);
|
|
57425
|
+
var id = lonlat && context.findRegion(lonlat[0], lonlat[1]);
|
|
57426
|
+
if (id != null && id !== -1 && ids.indexOf(id) == -1) ids.push(id);
|
|
57427
|
+
}
|
|
57428
|
+
}
|
|
57429
|
+
}
|
|
57430
|
+
|
|
57431
|
+
function projectPiecewiseMeshVertex(context, px, py, regionId) {
|
|
57432
|
+
var xy = rasterPixelToMapXY(context.grid, px, py);
|
|
57433
|
+
var lonlat = context.toGeographic(xy[0], xy[1]);
|
|
57434
|
+
var p, sourcePixel;
|
|
57435
|
+
if (!lonlat) return {sx: px, sy: py, x: NaN, y: NaN};
|
|
57436
|
+
if (context.projectRegion) {
|
|
57437
|
+
p = context.projectRegion(lonlat[0], lonlat[1], regionId);
|
|
57438
|
+
p = scaleRawProjectionPoint(context.destCRS, p);
|
|
57439
|
+
sourcePixel = [px, py];
|
|
57440
|
+
} else {
|
|
57441
|
+
lonlat = context.topology.constrainRegionPoint(lonlat[0], lonlat[1], regionId);
|
|
57442
|
+
xy = lonlat && context.fromGeographic(lonlat[0], lonlat[1]);
|
|
57443
|
+
p = lonlat && context.toDestination(lonlat[0], lonlat[1]);
|
|
57444
|
+
sourcePixel = xy && rasterMapXYToPixel(context.grid, xy[0], xy[1]);
|
|
57445
|
+
}
|
|
57446
|
+
return {
|
|
57447
|
+
sx: sourcePixel ? sourcePixel[0] : px,
|
|
57448
|
+
sy: sourcePixel ? sourcePixel[1] : py,
|
|
57449
|
+
x: p && isFinite(p[0]) ? p[0] : NaN,
|
|
57450
|
+
y: p && isFinite(p[1]) ? p[1] : NaN
|
|
57451
|
+
};
|
|
57452
|
+
}
|
|
57453
|
+
|
|
57454
|
+
function getProjectedRasterRegions(topology, regions, destCRS, toDestination) {
|
|
57455
|
+
return regions.map(function(region) {
|
|
57456
|
+
var boundary;
|
|
57457
|
+
if (region.projected_boundary) {
|
|
57458
|
+
boundary = region.projected_boundary.map(function(p) {
|
|
57459
|
+
return scaleRawProjectionPoint(destCRS, p);
|
|
57460
|
+
});
|
|
57461
|
+
} else {
|
|
57462
|
+
boundary = topology.getRegionBoundary(region.id).map(function(p) {
|
|
57463
|
+
var q = topology.constrainRegionPoint(p[0], p[1], region.id);
|
|
57464
|
+
return toDestination(q[0], q[1]);
|
|
57465
|
+
});
|
|
57466
|
+
}
|
|
57467
|
+
return {
|
|
57468
|
+
id: region.id,
|
|
57469
|
+
boundary: boundary
|
|
57470
|
+
};
|
|
57471
|
+
});
|
|
57472
|
+
}
|
|
57473
|
+
|
|
57474
|
+
function scaleRawProjectionPoint(P, p) {
|
|
57475
|
+
if (!p) return null;
|
|
57476
|
+
return [
|
|
57477
|
+
P.fr_meter * (P.a * p[0] + P.x0),
|
|
57478
|
+
P.fr_meter * (P.a * p[1] + P.y0)
|
|
57479
|
+
];
|
|
57480
|
+
}
|
|
57481
|
+
|
|
57482
|
+
function buildTopologyAwareProjectedRasterMesh(grid, srcCRS, destCRS, interval, optsArg) {
|
|
57483
|
+
var opts = optsArg || {};
|
|
57484
|
+
var topology = getProjectionTopology(destCRS);
|
|
57485
|
+
var findRegion = topology && (topology.findTransitionRegion || topology.findRegion);
|
|
57486
|
+
var wgs84 = parseCrsString$1('wgs84');
|
|
57487
|
+
var toGeographic = getProjTransform2(srcCRS, wgs84);
|
|
57488
|
+
var toDestination = getProjTransform2(wgs84, destCRS);
|
|
57489
|
+
var xs = getMeshStops(grid.width, interval);
|
|
57490
|
+
var ys = getMeshStops(grid.height, interval);
|
|
57491
|
+
var minCellSize = opts.raster_topology_min_cell_size ||
|
|
57492
|
+
opts.rasterTopologyMinCellSize ||
|
|
57493
|
+
DEFAULT_TOPOLOGY_MIN_CELL_SIZE;
|
|
57494
|
+
var mesh = {
|
|
57495
|
+
xs: xs,
|
|
57496
|
+
ys: ys,
|
|
57497
|
+
vertices: [],
|
|
57498
|
+
cells: [],
|
|
57499
|
+
topologyAware: true,
|
|
57500
|
+
subdivisionSkippedCellCount: 0
|
|
57501
|
+
};
|
|
57502
|
+
var context = {
|
|
57503
|
+
grid: grid,
|
|
57504
|
+
findRegion: findRegion,
|
|
57505
|
+
toGeographic: toGeographic,
|
|
57506
|
+
toDestination: toDestination,
|
|
57507
|
+
minCellSize: Math.max(0.01, minCellSize),
|
|
57508
|
+
maxDepth: MAX_TOPOLOGY_SUBDIVISION_DEPTH,
|
|
57509
|
+
mesh: mesh
|
|
57510
|
+
};
|
|
57511
|
+
if (!findRegion) return buildProjectedRasterMesh(grid, getProjTransform2(srcCRS, destCRS), interval);
|
|
57512
|
+
for (var y = 0; y < ys.length - 1; y++) {
|
|
57513
|
+
for (var x = 0; x < xs.length - 1; x++) {
|
|
57514
|
+
addTopologyMeshCell(context, xs[x], ys[y], xs[x + 1], ys[y + 1], 0);
|
|
57515
|
+
}
|
|
57516
|
+
}
|
|
57517
|
+
return mesh;
|
|
57518
|
+
}
|
|
57519
|
+
|
|
57520
|
+
function addTopologyMeshCell(context, x0, y0, x1, y1, depth) {
|
|
57521
|
+
var classification = classifyTopologyCell(context, x0, y0, x1, y1);
|
|
57522
|
+
var width = x1 - x0;
|
|
57523
|
+
var height = y1 - y0;
|
|
57524
|
+
var splitX = width > context.minCellSize && depth < context.maxDepth;
|
|
57525
|
+
var splitY = height > context.minCellSize && depth < context.maxDepth;
|
|
57526
|
+
if (classification.mixed && (splitX || splitY)) {
|
|
57527
|
+
subdivideTopologyMeshCell(context, x0, y0, x1, y1, depth, splitX, splitY);
|
|
57528
|
+
return;
|
|
57529
|
+
}
|
|
57530
|
+
if (classification.region == null || classification.mixed) {
|
|
57531
|
+
context.mesh.subdivisionSkippedCellCount++;
|
|
57532
|
+
return;
|
|
57533
|
+
}
|
|
57534
|
+
appendTopologyMeshCell(context, x0, y0, x1, y1, classification.region);
|
|
57535
|
+
}
|
|
57536
|
+
|
|
57537
|
+
function subdivideTopologyMeshCell(context, x0, y0, x1, y1, depth, splitX, splitY) {
|
|
57538
|
+
var xm = splitX ? (x0 + x1) / 2 : x1;
|
|
57539
|
+
var ym = splitY ? (y0 + y1) / 2 : y1;
|
|
57540
|
+
addTopologyMeshCell(context, x0, y0, xm, ym, depth + 1);
|
|
57541
|
+
if (splitX) addTopologyMeshCell(context, xm, y0, x1, ym, depth + 1);
|
|
57542
|
+
if (splitY) addTopologyMeshCell(context, x0, ym, xm, y1, depth + 1);
|
|
57543
|
+
if (splitX && splitY) addTopologyMeshCell(context, xm, ym, x1, y1, depth + 1);
|
|
57544
|
+
}
|
|
57545
|
+
|
|
57546
|
+
function classifyTopologyCell(context, x0, y0, x1, y1) {
|
|
57547
|
+
var cx = (x0 + x1) / 2;
|
|
57548
|
+
var cy = (y0 + y1) / 2;
|
|
57549
|
+
var region = getTopologyRegionAtPixel(context, cx, cy);
|
|
57550
|
+
var mixed = false;
|
|
57551
|
+
for (var iy = 0; iy <= TOPOLOGY_SAMPLE_STEPS && !mixed; iy++) {
|
|
57552
|
+
for (var ix = 0; ix <= TOPOLOGY_SAMPLE_STEPS; ix++) {
|
|
57553
|
+
var px = x0 + (x1 - x0) * ix / TOPOLOGY_SAMPLE_STEPS;
|
|
57554
|
+
var py = y0 + (y1 - y0) * iy / TOPOLOGY_SAMPLE_STEPS;
|
|
57555
|
+
px += (cx - px) * TOPOLOGY_VERTEX_INSET;
|
|
57556
|
+
py += (cy - py) * TOPOLOGY_VERTEX_INSET;
|
|
57557
|
+
if (getTopologyRegionAtPixel(context, px, py) !== region) {
|
|
57558
|
+
mixed = true;
|
|
57559
|
+
break;
|
|
57560
|
+
}
|
|
57561
|
+
}
|
|
57562
|
+
}
|
|
57563
|
+
return {region: region, mixed: mixed};
|
|
57564
|
+
}
|
|
57565
|
+
|
|
57566
|
+
function getTopologyRegionAtPixel(context, px, py) {
|
|
57567
|
+
var xy = rasterPixelToMapXY(context.grid, px, py);
|
|
57568
|
+
var lonlat = context.toGeographic(xy[0], xy[1]);
|
|
57569
|
+
if (!lonlat) return null;
|
|
57570
|
+
return context.findRegion(lonlat[0], lonlat[1]);
|
|
57571
|
+
}
|
|
57572
|
+
|
|
57573
|
+
function appendTopologyMeshCell(context, x0, y0, x1, y1, region) {
|
|
57574
|
+
var cx = (x0 + x1) / 2;
|
|
57575
|
+
var cy = (y0 + y1) / 2;
|
|
57576
|
+
var v00 = projectTopologyMeshVertex(context, x0, y0, cx, cy);
|
|
57577
|
+
var v10 = projectTopologyMeshVertex(context, x1, y0, cx, cy);
|
|
57578
|
+
var v01 = projectTopologyMeshVertex(context, x0, y1, cx, cy);
|
|
57579
|
+
var v11 = projectTopologyMeshVertex(context, x1, y1, cx, cy);
|
|
57580
|
+
var cell = {
|
|
57581
|
+
v00: v00,
|
|
57582
|
+
v10: v10,
|
|
57583
|
+
v01: v01,
|
|
57584
|
+
v11: v11,
|
|
57585
|
+
region: region,
|
|
57586
|
+
valid: vertexIsValid(v00) && vertexIsValid(v10) &&
|
|
57587
|
+
vertexIsValid(v01) && vertexIsValid(v11)
|
|
57588
|
+
};
|
|
57589
|
+
context.mesh.vertices.push(v00, v10, v01, v11);
|
|
57590
|
+
context.mesh.cells.push(cell);
|
|
57591
|
+
}
|
|
57592
|
+
|
|
57593
|
+
function projectTopologyMeshVertex(context, px, py, cx, cy) {
|
|
57594
|
+
var insetX = px + (cx - px) * TOPOLOGY_VERTEX_INSET;
|
|
57595
|
+
var insetY = py + (cy - py) * TOPOLOGY_VERTEX_INSET;
|
|
57596
|
+
var xy = rasterPixelToMapXY(context.grid, insetX, insetY);
|
|
57597
|
+
var lonlat = context.toGeographic(xy[0], xy[1]);
|
|
57598
|
+
var p = lonlat && context.toDestination(lonlat[0], lonlat[1]);
|
|
57599
|
+
return {
|
|
57600
|
+
sx: px,
|
|
57601
|
+
sy: py,
|
|
57602
|
+
x: p && isFinite(p[0]) ? p[0] : NaN,
|
|
57603
|
+
y: p && isFinite(p[1]) ? p[1] : NaN
|
|
57604
|
+
};
|
|
57605
|
+
}
|
|
57606
|
+
|
|
57607
|
+
function classifyRasterMesh(mesh, opts) {
|
|
57608
|
+
if (mesh.topologyAware) {
|
|
57609
|
+
classifyTopologyMeshCells(mesh);
|
|
57610
|
+
} else {
|
|
57611
|
+
classifyProjectedMeshCells(mesh, opts);
|
|
57612
|
+
}
|
|
57613
|
+
}
|
|
57614
|
+
|
|
57615
|
+
function classifyTopologyMeshCells(mesh) {
|
|
57616
|
+
var filtered = 0;
|
|
57617
|
+
mesh.cells.forEach(function(cell) {
|
|
57618
|
+
cell.maxEdge = getCellMaxEdge(cell);
|
|
57619
|
+
if (!cell.valid) {
|
|
57620
|
+
cell.valid = false;
|
|
57621
|
+
filtered++;
|
|
57622
|
+
}
|
|
57623
|
+
});
|
|
57624
|
+
// Topology-aware cells never span projection branches. Do not apply the
|
|
57625
|
+
// regular mesh's median-edge outlier filter here: adaptive subdivision
|
|
57626
|
+
// creates many small boundary cells that would make valid interior cells
|
|
57627
|
+
// appear to be outliers.
|
|
57628
|
+
mesh.maxEdge = Infinity;
|
|
57629
|
+
mesh.skippedCellCount = mesh.subdivisionSkippedCellCount + filtered;
|
|
57630
|
+
}
|
|
57631
|
+
|
|
55702
57632
|
function classifyProjectedMeshCells(mesh, opts) {
|
|
55703
57633
|
var cols = mesh.xs.length;
|
|
55704
57634
|
var cells = [];
|
|
@@ -55882,17 +57812,41 @@ ${svg}
|
|
|
55882
57812
|
];
|
|
55883
57813
|
}
|
|
55884
57814
|
|
|
57815
|
+
function rasterMapXYToPixel(grid, x, y) {
|
|
57816
|
+
var t = grid.transform;
|
|
57817
|
+
if (t) {
|
|
57818
|
+
return [
|
|
57819
|
+
(x - t[2]) / t[0],
|
|
57820
|
+
(y - t[5]) / t[4]
|
|
57821
|
+
];
|
|
57822
|
+
}
|
|
57823
|
+
return [
|
|
57824
|
+
(x - grid.bbox[0]) / (grid.bbox[2] - grid.bbox[0]) * grid.width,
|
|
57825
|
+
(grid.bbox[3] - y) / (grid.bbox[3] - grid.bbox[1]) * grid.height
|
|
57826
|
+
];
|
|
57827
|
+
}
|
|
57828
|
+
|
|
55885
57829
|
function getProjectedMeshBBox(mesh) {
|
|
55886
57830
|
var xmin = Infinity, ymin = Infinity, xmax = -Infinity, ymax = -Infinity;
|
|
55887
|
-
mesh.
|
|
55888
|
-
|
|
55889
|
-
|
|
55890
|
-
if (p.x < xmin) xmin = p.x;
|
|
55891
|
-
if (p.x > xmax) xmax = p.x;
|
|
55892
|
-
if (p.y < ymin) ymin = p.y;
|
|
55893
|
-
if (p.y > ymax) ymax = p.y;
|
|
57831
|
+
if (mesh.projectedRegions) {
|
|
57832
|
+
mesh.projectedRegions.forEach(function(region) {
|
|
57833
|
+
region.boundary.forEach(expand);
|
|
55894
57834
|
});
|
|
55895
|
-
}
|
|
57835
|
+
} else {
|
|
57836
|
+
mesh.cells.forEach(function(cell) {
|
|
57837
|
+
if (!cell.valid) return;
|
|
57838
|
+
[cell.v00, cell.v10, cell.v01, cell.v11].forEach(expand);
|
|
57839
|
+
});
|
|
57840
|
+
}
|
|
57841
|
+
function expand(p) {
|
|
57842
|
+
if (!p) return;
|
|
57843
|
+
var x = Array.isArray(p) ? p[0] : p.x;
|
|
57844
|
+
var y = Array.isArray(p) ? p[1] : p.y;
|
|
57845
|
+
if (x < xmin) xmin = x;
|
|
57846
|
+
if (x > xmax) xmax = x;
|
|
57847
|
+
if (y < ymin) ymin = y;
|
|
57848
|
+
if (y > ymax) ymax = y;
|
|
57849
|
+
}
|
|
55896
57850
|
return xmin < Infinity && xmax > xmin && ymax > ymin ? [xmin, ymin, xmax, ymax] : null;
|
|
55897
57851
|
}
|
|
55898
57852
|
|
|
@@ -55985,14 +57939,151 @@ ${svg}
|
|
|
55985
57939
|
}
|
|
55986
57940
|
|
|
55987
57941
|
function rasterizeProjectedMesh(srcGrid, destGrid, mesh, sampleMethod) {
|
|
57942
|
+
var regionData = mesh.projectedRegions ?
|
|
57943
|
+
createProjectedRegionMask(
|
|
57944
|
+
destGrid, mesh.projectedRegions, mesh.fillRegionMask) :
|
|
57945
|
+
null;
|
|
57946
|
+
(mesh.triangles || []).forEach(function(triangle) {
|
|
57947
|
+
if (!triangle.valid) return;
|
|
57948
|
+
var regionValue = regionData && regionData.values.get(triangle.region);
|
|
57949
|
+
rasterizeProjectedTriangle(
|
|
57950
|
+
srcGrid, destGrid, triangle.a, triangle.b, triangle.c,
|
|
57951
|
+
sampleMethod, regionData && regionData.mask, regionValue,
|
|
57952
|
+
mesh.sourceWrapX
|
|
57953
|
+
);
|
|
57954
|
+
});
|
|
55988
57955
|
mesh.cells.forEach(function(cell) {
|
|
55989
57956
|
if (!cell.valid) return;
|
|
55990
|
-
|
|
55991
|
-
rasterizeProjectedTriangle(
|
|
57957
|
+
var regionValue = regionData && regionData.values.get(cell.region);
|
|
57958
|
+
rasterizeProjectedTriangle(
|
|
57959
|
+
srcGrid, destGrid, cell.v00, cell.v10, cell.v11,
|
|
57960
|
+
sampleMethod, regionData && regionData.mask, regionValue, false
|
|
57961
|
+
);
|
|
57962
|
+
rasterizeProjectedTriangle(
|
|
57963
|
+
srcGrid, destGrid, cell.v00, cell.v11, cell.v01,
|
|
57964
|
+
sampleMethod, regionData && regionData.mask, regionValue, false
|
|
57965
|
+
);
|
|
55992
57966
|
});
|
|
55993
57967
|
}
|
|
55994
57968
|
|
|
55995
|
-
function
|
|
57969
|
+
function fillIsolatedProjectedRasterHoles(grid) {
|
|
57970
|
+
var holes = [];
|
|
57971
|
+
var width = grid.width;
|
|
57972
|
+
var height = grid.height;
|
|
57973
|
+
var coverage = grid.coverage;
|
|
57974
|
+
for (var y = 1; y < height - 1; y++) {
|
|
57975
|
+
for (var x = 1; x < width - 1; x++) {
|
|
57976
|
+
var i = y * width + x;
|
|
57977
|
+
if (!coverage[i] &&
|
|
57978
|
+
coverage[i - 1] && coverage[i + 1] &&
|
|
57979
|
+
coverage[i - width] && coverage[i + width]) {
|
|
57980
|
+
holes.push(i);
|
|
57981
|
+
}
|
|
57982
|
+
}
|
|
57983
|
+
}
|
|
57984
|
+
holes.forEach(function(i) {
|
|
57985
|
+
var src = (i - 1) * grid.bands;
|
|
57986
|
+
var dest = i * grid.bands;
|
|
57987
|
+
for (var band = 0; band < grid.bands; band++) {
|
|
57988
|
+
grid.samples[dest + band] = grid.samples[src + band];
|
|
57989
|
+
}
|
|
57990
|
+
coverage[i] = 1;
|
|
57991
|
+
});
|
|
57992
|
+
}
|
|
57993
|
+
|
|
57994
|
+
function fillProjectedRasterCoverage(grid) {
|
|
57995
|
+
// Used only for layouts whose projected outline fills the output rectangle.
|
|
57996
|
+
var width = grid.width;
|
|
57997
|
+
var height = grid.height;
|
|
57998
|
+
var coverage = grid.coverage;
|
|
57999
|
+
for (var y = 0; y < height; y++) {
|
|
58000
|
+
var row = y * width;
|
|
58001
|
+
var source = -1;
|
|
58002
|
+
for (var x = 0; x < width; x++) {
|
|
58003
|
+
var i = row + x;
|
|
58004
|
+
if (coverage[i]) {
|
|
58005
|
+
source = i;
|
|
58006
|
+
} else if (source >= 0) {
|
|
58007
|
+
copyProjectedRasterPixel(grid, source, i);
|
|
58008
|
+
}
|
|
58009
|
+
}
|
|
58010
|
+
source = -1;
|
|
58011
|
+
for (x = width - 1; x >= 0; x--) {
|
|
58012
|
+
i = row + x;
|
|
58013
|
+
if (coverage[i]) {
|
|
58014
|
+
source = i;
|
|
58015
|
+
} else if (source >= 0) {
|
|
58016
|
+
copyProjectedRasterPixel(grid, source, i);
|
|
58017
|
+
}
|
|
58018
|
+
}
|
|
58019
|
+
}
|
|
58020
|
+
}
|
|
58021
|
+
|
|
58022
|
+
function copyProjectedRasterPixel(grid, sourceIndex, destIndex) {
|
|
58023
|
+
var source = sourceIndex * grid.bands;
|
|
58024
|
+
var dest = destIndex * grid.bands;
|
|
58025
|
+
for (var band = 0; band < grid.bands; band++) {
|
|
58026
|
+
grid.samples[dest + band] = grid.samples[source + band];
|
|
58027
|
+
}
|
|
58028
|
+
grid.coverage[destIndex] = 1;
|
|
58029
|
+
}
|
|
58030
|
+
|
|
58031
|
+
function createProjectedRegionMask(grid, regions, fill) {
|
|
58032
|
+
var mask = new Uint8Array(grid.width * grid.height);
|
|
58033
|
+
var values = new Map();
|
|
58034
|
+
regions.forEach(function(region, i) {
|
|
58035
|
+
var value = i + 1;
|
|
58036
|
+
values.set(region.id, value);
|
|
58037
|
+
rasterizeRegionMask(grid, mask, region.boundary, value);
|
|
58038
|
+
});
|
|
58039
|
+
if (fill) fillRegionMask(mask, grid.width, grid.height);
|
|
58040
|
+
return {mask: mask, values: values};
|
|
58041
|
+
}
|
|
58042
|
+
|
|
58043
|
+
function fillRegionMask(mask, width, height) {
|
|
58044
|
+
for (var y = 0; y < height; y++) {
|
|
58045
|
+
var row = y * width;
|
|
58046
|
+
var value = 0;
|
|
58047
|
+
for (var x = 0; x < width; x++) {
|
|
58048
|
+
if (mask[row + x]) value = mask[row + x];
|
|
58049
|
+
else if (value) mask[row + x] = value;
|
|
58050
|
+
}
|
|
58051
|
+
value = 0;
|
|
58052
|
+
for (x = width - 1; x >= 0; x--) {
|
|
58053
|
+
if (mask[row + x]) value = mask[row + x];
|
|
58054
|
+
else if (value) mask[row + x] = value;
|
|
58055
|
+
}
|
|
58056
|
+
}
|
|
58057
|
+
}
|
|
58058
|
+
|
|
58059
|
+
function rasterizeRegionMask(grid, mask, boundary, value) {
|
|
58060
|
+
var ring = boundary.map(function(p) {
|
|
58061
|
+
return mapXYToRasterPixel(grid, p[0], p[1]);
|
|
58062
|
+
});
|
|
58063
|
+
var ymin = Math.max(0, Math.floor(Math.min.apply(null, ring.map(function(p) { return p[1]; }))));
|
|
58064
|
+
var ymax = Math.min(grid.height - 1, Math.ceil(Math.max.apply(null, ring.map(function(p) { return p[1]; }))));
|
|
58065
|
+
var intersections = [];
|
|
58066
|
+
for (var y = ymin; y <= ymax; y++) {
|
|
58067
|
+
var py = y + 0.5;
|
|
58068
|
+
intersections.length = 0;
|
|
58069
|
+
for (var i = 1; i < ring.length; i++) {
|
|
58070
|
+
var a = ring[i - 1];
|
|
58071
|
+
var b = ring[i];
|
|
58072
|
+
if ((a[1] > py) == (b[1] > py)) continue;
|
|
58073
|
+
intersections.push(a[0] + (py - a[1]) * (b[0] - a[0]) / (b[1] - a[1]));
|
|
58074
|
+
}
|
|
58075
|
+
intersections.sort(function(a, b) { return a - b; });
|
|
58076
|
+
for (var j = 1; j < intersections.length; j += 2) {
|
|
58077
|
+
var x0 = Math.max(0, Math.ceil(intersections[j - 1] - 0.5));
|
|
58078
|
+
var x1 = Math.min(grid.width - 1, Math.floor(intersections[j] - 0.5));
|
|
58079
|
+
for (var x = x0; x <= x1; x++) {
|
|
58080
|
+
mask[y * grid.width + x] = value;
|
|
58081
|
+
}
|
|
58082
|
+
}
|
|
58083
|
+
}
|
|
58084
|
+
}
|
|
58085
|
+
|
|
58086
|
+
function rasterizeProjectedTriangle(srcGrid, destGrid, a, b, c, sampleMethod, regionMask, regionValue, sourceWrapX) {
|
|
55996
58087
|
var bbox, x0, x1, y0, y1, det, w1, w2, w3, sx, sy, ap, bp, cp;
|
|
55997
58088
|
if (!vertexIsValid(a) || !vertexIsValid(b) || !vertexIsValid(c)) return;
|
|
55998
58089
|
ap = vertexToDestPixel(destGrid, a);
|
|
@@ -56004,13 +58095,15 @@ ${svg}
|
|
|
56004
58095
|
x0 = bbox[0]; y0 = bbox[1]; x1 = bbox[2]; y1 = bbox[3];
|
|
56005
58096
|
for (var y = y0; y <= y1; y++) {
|
|
56006
58097
|
for (var x = x0; x <= x1; x++) {
|
|
58098
|
+
if (regionMask && regionMask[y * destGrid.width + x] != regionValue) continue;
|
|
56007
58099
|
w1 = edgeFunction(bp, cp, x + 0.5, y + 0.5) / det;
|
|
56008
58100
|
w2 = edgeFunction(cp, ap, x + 0.5, y + 0.5) / det;
|
|
56009
58101
|
w3 = 1 - w1 - w2;
|
|
56010
58102
|
if (w1 < -1e-9 || w2 < -1e-9 || w3 < -1e-9) continue;
|
|
56011
58103
|
sx = w1 * a.sx + w2 * b.sx + w3 * c.sx;
|
|
56012
58104
|
sy = w1 * a.sy + w2 * b.sy + w3 * c.sy;
|
|
56013
|
-
copyRasterSample(
|
|
58105
|
+
copyRasterSample(
|
|
58106
|
+
srcGrid, destGrid, sx, sy, x, y, sampleMethod, sourceWrapX);
|
|
56014
58107
|
}
|
|
56015
58108
|
}
|
|
56016
58109
|
}
|
|
@@ -56042,16 +58135,18 @@ ${svg}
|
|
|
56042
58135
|
];
|
|
56043
58136
|
}
|
|
56044
58137
|
|
|
56045
|
-
function copyRasterSample(srcGrid, destGrid, sx, sy, dx, dy, sampleMethod) {
|
|
58138
|
+
function copyRasterSample(srcGrid, destGrid, sx, sy, dx, dy, sampleMethod, wrapX) {
|
|
56046
58139
|
if (sampleMethod == 'bilinear') {
|
|
56047
|
-
copyBilinearRasterSample(srcGrid, destGrid, sx, sy, dx, dy);
|
|
58140
|
+
copyBilinearRasterSample(srcGrid, destGrid, sx, sy, dx, dy, wrapX);
|
|
56048
58141
|
} else {
|
|
56049
|
-
copyNearestRasterSample(srcGrid, destGrid, sx, sy, dx, dy);
|
|
58142
|
+
copyNearestRasterSample(srcGrid, destGrid, sx, sy, dx, dy, wrapX);
|
|
56050
58143
|
}
|
|
56051
58144
|
}
|
|
56052
58145
|
|
|
56053
|
-
function copyNearestRasterSample(srcGrid, destGrid, sx, sy, dx, dy) {
|
|
56054
|
-
var srcX =
|
|
58146
|
+
function copyNearestRasterSample(srcGrid, destGrid, sx, sy, dx, dy, wrapX) {
|
|
58147
|
+
var srcX = wrapX ?
|
|
58148
|
+
modulo(Math.floor(sx), srcGrid.width) :
|
|
58149
|
+
clamp$1(Math.floor(sx), 0, srcGrid.width - 1);
|
|
56055
58150
|
var srcY = clamp$1(Math.floor(sy), 0, srcGrid.height - 1);
|
|
56056
58151
|
var src = (srcY * srcGrid.width + srcX) * srcGrid.bands;
|
|
56057
58152
|
var dest = (dy * destGrid.width + dx) * destGrid.bands;
|
|
@@ -56063,10 +58158,14 @@ ${svg}
|
|
|
56063
58158
|
if (destGrid.coverage) destGrid.coverage[dy * destGrid.width + dx] = 1;
|
|
56064
58159
|
}
|
|
56065
58160
|
|
|
56066
|
-
function copyBilinearRasterSample(srcGrid, destGrid, sx, sy, dx, dy) {
|
|
56067
|
-
|
|
58161
|
+
function copyBilinearRasterSample(srcGrid, destGrid, sx, sy, dx, dy, wrapX) {
|
|
58162
|
+
if (wrapX) sx = modulo(sx, srcGrid.width);
|
|
58163
|
+
var srcX = wrapX ?
|
|
58164
|
+
modulo(Math.floor(sx - 0.5), srcGrid.width) :
|
|
58165
|
+
clamp$1(Math.floor(sx - 0.5), 0, srcGrid.width - 1);
|
|
56068
58166
|
var srcY = clamp$1(Math.floor(sy - 0.5), 0, srcGrid.height - 1);
|
|
56069
|
-
var srcX2 =
|
|
58167
|
+
var srcX2 = wrapX ? (srcX + 1) % srcGrid.width :
|
|
58168
|
+
clamp$1(srcX + 1, 0, srcGrid.width - 1);
|
|
56070
58169
|
var srcY2 = clamp$1(srcY + 1, 0, srcGrid.height - 1);
|
|
56071
58170
|
var tx = clamp$1(sx - 0.5 - srcX, 0, 1);
|
|
56072
58171
|
var ty = clamp$1(sy - 0.5 - srcY, 0, 1);
|
|
@@ -56178,14 +58277,133 @@ ${svg}
|
|
|
56178
58277
|
return val < min ? min : val > max ? max : val;
|
|
56179
58278
|
}
|
|
56180
58279
|
|
|
58280
|
+
function modulo(val, base) {
|
|
58281
|
+
return (val % base + base) % base;
|
|
58282
|
+
}
|
|
58283
|
+
|
|
56181
58284
|
var RasterReprojection = /*#__PURE__*/Object.freeze({
|
|
56182
58285
|
__proto__: null,
|
|
56183
58286
|
buildProjectedRasterMesh: buildProjectedRasterMesh,
|
|
58287
|
+
buildTopologyAwareProjectedRasterMesh: buildTopologyAwareProjectedRasterMesh,
|
|
56184
58288
|
getProjectedRasterGridBBox: getProjectedRasterGridBBox,
|
|
56185
58289
|
getProjectedRasterMeshBBox: getProjectedRasterMeshBBox,
|
|
56186
58290
|
projectRasterGridForward: projectRasterGridForward
|
|
56187
58291
|
});
|
|
56188
58292
|
|
|
58293
|
+
function splitPolygonFrameChords(dataset, bounds) {
|
|
58294
|
+
var editor = new DatasetEditor(dataset);
|
|
58295
|
+
dataset.layers.forEach(function(lyr) {
|
|
58296
|
+
if (lyr.geometry_type == 'polygon') {
|
|
58297
|
+
editor.editLayer(lyr, function(path) {
|
|
58298
|
+
return splitRingAtFrameChords(path, bounds);
|
|
58299
|
+
});
|
|
58300
|
+
} else {
|
|
58301
|
+
editor.editLayer(lyr, function(geometry) {
|
|
58302
|
+
return lyr.geometry_type == 'point' ? geometry : [geometry];
|
|
58303
|
+
});
|
|
58304
|
+
}
|
|
58305
|
+
});
|
|
58306
|
+
editor.done();
|
|
58307
|
+
}
|
|
58308
|
+
|
|
58309
|
+
function splitRingAtFrameChords(path, bounds, depth) {
|
|
58310
|
+
depth = depth || 0;
|
|
58311
|
+
var closed = pointsEqual(path[0], path[path.length - 1]);
|
|
58312
|
+
var n = path.length - (closed ? 1 : 0);
|
|
58313
|
+
if (n < 4) return [path];
|
|
58314
|
+
var width = bounds[2] - bounds[0];
|
|
58315
|
+
var height = bounds[3] - bounds[1];
|
|
58316
|
+
var tolerance = Math.max(width, height) * 1e-3;
|
|
58317
|
+
var edgesBySide = [[], [], [], []];
|
|
58318
|
+
for (var i = 0; i < n; i++) {
|
|
58319
|
+
var side = getFrameSide(
|
|
58320
|
+
path[i], path[(i + 1) % n], bounds, tolerance);
|
|
58321
|
+
if (side >= 0) edgesBySide[side].push({index: i, side: side});
|
|
58322
|
+
}
|
|
58323
|
+
for (var frameSide = 0; frameSide < edgesBySide.length; frameSide++) {
|
|
58324
|
+
var runs = groupEdgeRuns(edgesBySide[frameSide], n);
|
|
58325
|
+
if (runs.length > 1) {
|
|
58326
|
+
var parts = splitRingAtRuns(path, n, runs, frameSide, bounds);
|
|
58327
|
+
if (depth >= 3) return parts;
|
|
58328
|
+
return parts.reduce(function(memo, part) {
|
|
58329
|
+
return memo.concat(splitRingAtFrameChords(part, bounds, depth + 1));
|
|
58330
|
+
}, []);
|
|
58331
|
+
}
|
|
58332
|
+
}
|
|
58333
|
+
return [path];
|
|
58334
|
+
}
|
|
58335
|
+
|
|
58336
|
+
function splitRingAtRuns(path, n, runs, side, bounds) {
|
|
58337
|
+
return runs.map(function(run, i) {
|
|
58338
|
+
var next = runs[(i + 1) % runs.length];
|
|
58339
|
+
var start = (run.end + 1) % n;
|
|
58340
|
+
var end = next.start;
|
|
58341
|
+
var part = [];
|
|
58342
|
+
var j = start;
|
|
58343
|
+
while (true) {
|
|
58344
|
+
part.push(path[j].concat());
|
|
58345
|
+
if (j == end) break;
|
|
58346
|
+
j = (j + 1) % n;
|
|
58347
|
+
}
|
|
58348
|
+
if (side == 0 || side == 2) {
|
|
58349
|
+
var y = side == 0 ? bounds[1] : bounds[3];
|
|
58350
|
+
part[0][1] = y;
|
|
58351
|
+
part[part.length - 1][1] = y;
|
|
58352
|
+
} else {
|
|
58353
|
+
var x = side == 1 ? bounds[2] : bounds[0];
|
|
58354
|
+
part[0][0] = x;
|
|
58355
|
+
part[part.length - 1][0] = x;
|
|
58356
|
+
}
|
|
58357
|
+
part.push(part[0].concat());
|
|
58358
|
+
return part;
|
|
58359
|
+
}).filter(function(part) {
|
|
58360
|
+
return part.length > 3;
|
|
58361
|
+
});
|
|
58362
|
+
}
|
|
58363
|
+
|
|
58364
|
+
function getFrameSide(a, b, bounds, tolerance) {
|
|
58365
|
+
var dx = Math.abs(a[0] - b[0]);
|
|
58366
|
+
var dy = Math.abs(a[1] - b[1]);
|
|
58367
|
+
var width = bounds[2] - bounds[0];
|
|
58368
|
+
var height = bounds[3] - bounds[1];
|
|
58369
|
+
if (dx > width * 0.2) {
|
|
58370
|
+
if (Math.abs(a[1] - bounds[1]) < tolerance &&
|
|
58371
|
+
Math.abs(b[1] - bounds[1]) < tolerance) return 0;
|
|
58372
|
+
if (Math.abs(a[1] - bounds[3]) < tolerance &&
|
|
58373
|
+
Math.abs(b[1] - bounds[3]) < tolerance) return 2;
|
|
58374
|
+
}
|
|
58375
|
+
if (dy > height * 0.2) {
|
|
58376
|
+
if (Math.abs(a[0] - bounds[2]) < tolerance &&
|
|
58377
|
+
Math.abs(b[0] - bounds[2]) < tolerance) return 1;
|
|
58378
|
+
if (Math.abs(a[0] - bounds[0]) < tolerance &&
|
|
58379
|
+
Math.abs(b[0] - bounds[0]) < tolerance) return 3;
|
|
58380
|
+
}
|
|
58381
|
+
return -1;
|
|
58382
|
+
}
|
|
58383
|
+
|
|
58384
|
+
function groupEdgeRuns(edges, n) {
|
|
58385
|
+
var runs = [];
|
|
58386
|
+
edges.forEach(function(edge) {
|
|
58387
|
+
var run = runs[runs.length - 1];
|
|
58388
|
+
if (run && edge.side == run.side && edge.index == run.end + 1) {
|
|
58389
|
+
run.end = edge.index;
|
|
58390
|
+
} else {
|
|
58391
|
+
runs.push({start: edge.index, end: edge.index, side: edge.side});
|
|
58392
|
+
}
|
|
58393
|
+
});
|
|
58394
|
+
if (runs.length > 1 && runs[0].start == 0 &&
|
|
58395
|
+
runs[runs.length - 1].end == n - 1 &&
|
|
58396
|
+
runs[0].side == runs[runs.length - 1].side) {
|
|
58397
|
+
runs[0].start = runs[runs.length - 1].start;
|
|
58398
|
+
runs.pop();
|
|
58399
|
+
}
|
|
58400
|
+
return runs;
|
|
58401
|
+
}
|
|
58402
|
+
|
|
58403
|
+
function pointsEqual(a, b) {
|
|
58404
|
+
return a && b && a[0] == b[0] && a[1] == b[1];
|
|
58405
|
+
}
|
|
58406
|
+
|
|
56189
58407
|
cmd.proj = function(dataset, catalog, opts, targetLayers) {
|
|
56190
58408
|
var srcInfo, destInfo, destStr;
|
|
56191
58409
|
var implicitlyProjectedNames = getImplicitlyTargetedLayerNames(dataset, targetLayers, layerHasGeometry);
|
|
@@ -56331,9 +58549,6 @@ ${svg}
|
|
|
56331
58549
|
if (isProjectedCRS(src) && !isInvertibleCRS(src)) {
|
|
56332
58550
|
stop$1('Unable to project from a coordinate system that has no inverse transform');
|
|
56333
58551
|
}
|
|
56334
|
-
if (isInterruptedProjection(dest) && dataset.layers.some(layerHasRaster)) {
|
|
56335
|
-
stop$1('Raster reprojection is not currently supported for interrupted projections');
|
|
56336
|
-
}
|
|
56337
58552
|
var proj = getProjTransform2(src, dest); // v2 returns null points instead of throwing an error
|
|
56338
58553
|
var badArcs = 0;
|
|
56339
58554
|
var badPoints = 0;
|
|
@@ -56356,6 +58571,12 @@ ${svg}
|
|
|
56356
58571
|
}
|
|
56357
58572
|
}
|
|
56358
58573
|
|
|
58574
|
+
var frameBounds = dest.__projection_topology &&
|
|
58575
|
+
dest.__projection_topology.frame_bounds;
|
|
58576
|
+
if (clipped && dataset.arcs && frameBounds) {
|
|
58577
|
+
splitPolygonFrameChords(dataset, scaleProjectionFrameBounds(frameBounds, dest));
|
|
58578
|
+
}
|
|
58579
|
+
|
|
56359
58580
|
if (clipped) {
|
|
56360
58581
|
// TODO: could more selective in cleaning clipped layers
|
|
56361
58582
|
// (probably only needed when clipped area crosses the antimeridian or includes a pole)
|
|
@@ -56371,6 +58592,18 @@ ${svg}
|
|
|
56371
58592
|
dataset.info.crs = dest;
|
|
56372
58593
|
}
|
|
56373
58594
|
|
|
58595
|
+
function scaleProjectionFrameBounds(bounds, crs) {
|
|
58596
|
+
var scale = crs.a * crs.fr_meter;
|
|
58597
|
+
var dx = crs.x0 * crs.fr_meter;
|
|
58598
|
+
var dy = crs.y0 * crs.fr_meter;
|
|
58599
|
+
return [
|
|
58600
|
+
bounds[0] * scale + dx,
|
|
58601
|
+
bounds[1] * scale + dy,
|
|
58602
|
+
bounds[2] * scale + dx,
|
|
58603
|
+
bounds[3] * scale + dy
|
|
58604
|
+
];
|
|
58605
|
+
}
|
|
58606
|
+
|
|
56374
58607
|
function projectRasterLayer(lyr, src, dest, opts) {
|
|
56375
58608
|
var raster = lyr.raster;
|
|
56376
58609
|
raster.grid = projectRasterGridForward(raster, src, dest, opts || {});
|
|
@@ -60733,7 +62966,7 @@ ${svg}
|
|
|
60733
62966
|
// Isometric ("Mercator-stretched") latitude in degrees-in; returns +/-Infinity at
|
|
60734
62967
|
// the poles.
|
|
60735
62968
|
function isometricLatitude(latDeg) {
|
|
60736
|
-
return Math.log(Math.tan(Math.PI / 4 + latDeg * D2R$
|
|
62969
|
+
return Math.log(Math.tan(Math.PI / 4 + latDeg * D2R$8 / 2));
|
|
60737
62970
|
}
|
|
60738
62971
|
|
|
60739
62972
|
// Rhumb-line (loxodrome) interpolation, fraction k of the way from A to B.
|
|
@@ -60758,9 +62991,9 @@ ${svg}
|
|
|
60758
62991
|
// Rhumb-line distance in meters, using the raw longitude delta (so a full-parallel
|
|
60759
62992
|
// sweep returns the parallel's length rather than 0).
|
|
60760
62993
|
function rhumbDistance(a, b) {
|
|
60761
|
-
var phi1 = a[1] * D2R$
|
|
62994
|
+
var phi1 = a[1] * D2R$8, phi2 = b[1] * D2R$8;
|
|
60762
62995
|
var dPhi = phi2 - phi1;
|
|
60763
|
-
var dLambda = (b[0] - a[0]) * D2R$
|
|
62996
|
+
var dLambda = (b[0] - a[0]) * D2R$8; // raw
|
|
60764
62997
|
var dPsi = Math.log(Math.tan(Math.PI / 4 + phi2 / 2) / Math.tan(Math.PI / 4 + phi1 / 2));
|
|
60765
62998
|
var q = Math.abs(dPsi) > 1e-12 ? dPhi / dPsi : Math.cos(phi1);
|
|
60766
62999
|
return Math.sqrt(dPhi * dPhi + q * q * dLambda * dLambda) * R$3;
|
|
@@ -64470,7 +66703,10 @@ ${svg}
|
|
|
64470
66703
|
var src = parseCrsString$1('wgs84');
|
|
64471
66704
|
var outline = getOutlineDataset(src, dest, {});
|
|
64472
66705
|
var graticule = importGeoJSON(createGraticule(dest, !!outline, opts));
|
|
64473
|
-
projectDataset(graticule, src, dest, {
|
|
66706
|
+
projectDataset(graticule, src, dest, {
|
|
66707
|
+
no_clip: false,
|
|
66708
|
+
densify: isInterruptedProjection(dest)
|
|
66709
|
+
});
|
|
64474
66710
|
if (outline) {
|
|
64475
66711
|
graticule = addOutlineToGraticule(graticule, outline);
|
|
64476
66712
|
}
|
|
@@ -71096,7 +73332,7 @@ ${svg}
|
|
|
71096
73332
|
return name == 'rectangle' || name == 'rectangles' || name == 'filter' && opts.cleanup;
|
|
71097
73333
|
}
|
|
71098
73334
|
|
|
71099
|
-
var version = "0.7.
|
|
73335
|
+
var version = "0.7.48";
|
|
71100
73336
|
|
|
71101
73337
|
// Parse command line args into commands and run them
|
|
71102
73338
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|