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.
Files changed (3) hide show
  1. package/mapshaper.js +2466 -230
  2. package/package.json +1 -1
  3. 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$4(val, min, max) {
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$4(rank | 0, 1, arr.length);
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$4, cleanNumericString, contains, copyElements, countValues, createBuffer,
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$7 = Math.PI / 180;
2057
- var R2D$6 = 180 / Math.PI;
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$7 * R$3;
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$7;
2209
- var lng = Math.atan2(y / d, x / d) / D2R$7;
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$7;
2217
- lat *= D2R$7;
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$7,
2337
+ D2R: D2R$8,
2338
2338
  R: R$3,
2339
- R2D: R2D$6,
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$6 = Math.PI / 180;
6268
- var R2D$5 = 180 / Math.PI;
6269
- var EPS$2 = 1e-12;
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$6, p[1] * D2R$6);
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$6, p[1] * D2R$6);
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$6, p[1] * D2R$6);
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$6;
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$6,
6357
- config.rotation[1] * D2R$6,
6358
- config.rotation[2] * D2R$6
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
- var p = face.project(rotated[0], rotated[1]);
6363
- p = applyMatrix(face.transform, p);
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$6,
6375
- config.rotation[1] * D2R$6,
6376
- config.rotation[2] * D2R$6
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$6,
6387
- config.rotation[1] * D2R$6,
6388
- config.rotation[2] * D2R$6
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$6,
6431
- p[1] * D2R$6,
6432
- config.rotation[0] * D2R$6,
6433
- config.rotation[1] * D2R$6,
6434
- config.rotation[2] * D2R$6,
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$2(q[0] * R2D$5 + lon0), q[1] * R2D$5];
6486
+ return [normalizeLongitude$3(q[0] * R2D$6 + lon0), q[1] * R2D$6];
6438
6487
  });
6439
- var paths = splitPathAtAntimeridian$2(
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 {id: face.id};
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$2(lon - lon0) * D2R$6;
6465
- return findFace(lam, lat * D2R$6);
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$2(lon - lon0) * D2R$6;
6469
- return findTransitionRegion(lam, lat * D2R$6);
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$6,
6488
- (rotation[1] || 0) * D2R$6,
6489
- (rotation[2] || 0) * D2R$6,
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$2) return false;
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$6, a[1] * D2R$6)),
6563
- applyMatrix(face.transform, face.project(b[0] * D2R$6, b[1] * D2R$6))
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$3(k * cosDeltaPhi - x * sinDeltaPhi, -1, 1))
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$3(k * cosDeltaGamma + y * sinDeltaGamma, -1, 1))
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$3(dot$2(av, bv), -1, 1));
6727
- var n = Math.max(1, Math.ceil(angle * R2D$5 / interval));
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$2) {
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$2(path) {
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$3(dot$2(degreesToVector$2(a[0], a[1]),
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$6, lat * D2R$6);
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$5,
6801
- Math.asin(clamp$3(p[2], -1, 1)) * R2D$5
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$2 && Math.abs(a[1] - b[1]) < EPS$2;
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$2(lon) {
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$3(val, min, max) {
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$5 = Math.PI / 180;
6879
- var R2D$4 = 180 / Math.PI;
6880
- var SQRT3$1 = Math.sqrt(3);
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$2 = {};
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$2[method]) {
6993
+ if (!engines$3[method]) {
6912
6994
  var data = createAiroceanFaces();
6913
- engines$2[method] = createPolyhedralProjection({
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$2[method];
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$4);
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$4;
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$1 + GRAY_EL / 3 - GRAY_EL / 2, GRAY_DVE);
7043
- var a2p = Math.atan2(x - y / SQRT3$1 + GRAY_EL / 3 - GRAY_EL / 2, GRAY_DVE);
7044
- var a3p = Math.atan2(GRAY_EL / 3 - x - y / SQRT3$1 - GRAY_EL / 2, GRAY_DVE);
7045
- return [SQRT3$1 * (a2p - a3p), 2 * a1p - a2p - a3p];
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$5;
7071
- var phi = p[1] * D2R$5;
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$4,
7079
- Math.asin(Math.max(-1, Math.min(1, p[2]))) * R2D$4
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$4 = Math.PI / 180;
7128
- var R2D$3 = 180 / Math.PI;
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$3;
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$3));
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$3, phi * R2D$3);
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$4)];
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$4),
7175
- pointN[1] - CK.lengthMA * Math.cos(30 * D2R$4)
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$4),
7186
- CK.pointA[1] + CK.lengthAP73 * Math.sin(30 * D2R$4)
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$4),
7428
- origin[1] + length * Math.sin(angle * D2R$4)
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$4);
7446
- var sin = Math.sin(angle * D2R$4);
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$4);
7468
- var m2 = Math.tan(slope2 * D2R$4);
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$3 = Math.PI / 180;
7497
- var EPS$1 = 1e-12;
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$3, p[1] * D2R$3);
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$1) return [0, 0];
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$3;
7617
- var phi = p[1] * D2R$3;
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$3,
7626
- Math.atan2(sum[2], Math.hypot(sum[0], sum[1])) / D2R$3
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$2 = Math.PI / 180;
7642
- var R2D$2 = 180 / Math.PI;
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$1 = {};
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$1[key]) {
7751
+ if (!engines$2[key]) {
7670
7752
  if (key == 'cahill_keyes') {
7671
- engines$1[key] = createCahillKeyesEngine();
7753
+ engines$2[key] = createCahillKeyesEngine();
7672
7754
  } else if (key == 'butterfly') {
7673
- engines$1[key] = createButterflyEngine();
7755
+ engines$2[key] = createButterflyEngine();
7674
7756
  } else {
7675
7757
  throw new Error('Unknown butterfly projection: ' + method);
7676
7758
  }
7677
7759
  }
7678
- return engines$1[key];
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$2;
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$2);
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$2),
7712
- Math.sin(17 * D2R$2),
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$2;
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$2, p[1] * D2R$2);
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$2),
7830
- Math.sin(17 * D2R$2),
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$2, p[1] * D2R$2);
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$2;
8010
- var phi = p[1] * D2R$2;
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$2,
8018
- Math.asin(Math.max(-1, Math.min(1, p[2]))) * R2D$2
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$1 = Math.PI / 180;
8072
- var R2D$1 = 180 / Math.PI;
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$1);
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$1);
8200
- return projectState(lam, lat * D2R$1).region;
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 = Math.floor((relative[1] + Math.PI / 3) / (2 * Math.PI / 3));
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$2(x, XMIN, XMAX);
8243
- y = clamp$2(y, YMIN, YMAX);
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.id,
8248
- sector: mod(sector, 3),
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$2(dot$1(v, orientation.z), -1, 1))
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$2(p[2], -1, 1))];
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$2(
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$2(value, -1, 1)) - Math.PI;
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$2(
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$2(value, -1, 1));
8411
- else lonOut = lon0 - Math.acos(clamp$2(value, -1, 1));
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$1(p[0] * R2D$1 + lon0),
8435
- p[1] * R2D$1
8952
+ normalizeLongitude$2(p[0] * R2D$2 + lon0),
8953
+ p[1] * R2D$2
8436
8954
  ]);
8437
8955
  }
8438
- return memo.concat(splitPathAtAntimeridian$1(path));
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$1(path) {
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$1, p[0] * D2R$1);
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$1(lon) {
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$2(value, min, max) {
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$6;
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$7 * R$3, Math.log(Math.tan(Math.PI / 4 + y * D2R$7 / 2)) * R$3] :
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$7 * R$3), (2 * Math.atan(Math.exp(y / R$3)) - Math.PI / 2) / (D2R$7)] :
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$6 >= 90 - POLAR_BUFFER_MARGIN_DEGREES;
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$6;
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$7,
54390
- b = (rotation[1] || 0) * D2R$7,
54391
- c = (rotation[2] || 0) * D2R$7;
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$7;
54394
- p[1] *= D2R$7;
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$6;
54398
- p[1] *= R2D$6;
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 = buildProjectedRasterMesh(grid, transform, interval);
55625
- classifyProjectedMeshCells(mesh, opts);
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 = buildProjectedRasterMesh(grid, transform, interval);
55676
- classifyProjectedMeshCells(mesh, opts);
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
- classifyProjectedMeshCells(mesh, optsArg || {});
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.cells.forEach(function(cell) {
55888
- if (!cell.valid) return;
55889
- [cell.v00, cell.v10, cell.v01, cell.v11].forEach(function(p) {
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
- rasterizeProjectedTriangle(srcGrid, destGrid, cell.v00, cell.v10, cell.v11, sampleMethod);
55991
- rasterizeProjectedTriangle(srcGrid, destGrid, cell.v00, cell.v11, cell.v01, sampleMethod);
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 rasterizeProjectedTriangle(srcGrid, destGrid, a, b, c, sampleMethod) {
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(srcGrid, destGrid, sx, sy, x, y, sampleMethod);
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 = clamp$1(Math.floor(sx), 0, srcGrid.width - 1);
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
- var srcX = clamp$1(Math.floor(sx - 0.5), 0, srcGrid.width - 1);
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 = clamp$1(srcX + 1, 0, srcGrid.width - 1);
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$7 / 2));
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$7, phi2 = b[1] * D2R$7;
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$7; // raw
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, {no_clip: false}); // TODO: densify?
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.46";
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.