mapshaper 0.7.45 → 0.7.47

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