mapshaper 0.7.47 → 0.7.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/mapshaper.js +549 -80
  2. package/package.json +1 -1
  3. package/www/mapshaper.js +549 -80
package/mapshaper.js CHANGED
@@ -78,7 +78,7 @@
78
78
  return obj === Object(obj); // via underscore
79
79
  }
80
80
 
81
- function clamp$4(val, min, max) {
81
+ function clamp$5(val, min, max) {
82
82
  return val < min ? min : (val > max ? max : val);
83
83
  }
84
84
 
@@ -721,7 +721,7 @@
721
721
  function findValueByRank(arr, rank) {
722
722
  if (!arr.length || rank < 1 || rank > arr.length) error$1("[findValueByRank()] invalid input");
723
723
 
724
- rank = clamp$4(rank | 0, 1, arr.length);
724
+ rank = clamp$5(rank | 0, 1, arr.length);
725
725
  var k = rank - 1, // conv. rank to array index
726
726
  n = arr.length,
727
727
  l = 0,
@@ -1095,7 +1095,7 @@
1095
1095
  // self-import and the resulting Rollup circular-dependency warning.
1096
1096
  var utils = {
1097
1097
  addThousandsSep, addslashes, arrayToIndex,
1098
- clamp: clamp$4, cleanNumericString, contains, copyElements, countValues, createBuffer,
1098
+ clamp: clamp$5, cleanNumericString, contains, copyElements, countValues, createBuffer,
1099
1099
  defaults, difference,
1100
1100
  endsWith, every, expandoBuffer, extend: extend$1, extendBuffer,
1101
1101
  find: find$1, findMedian, findQuantile, findRankByValue, findStringPrefix,
@@ -6345,6 +6345,7 @@
6345
6345
  outline: outline,
6346
6346
  forward: forward,
6347
6347
  forwardFace: forwardFace,
6348
+ invertFace: invertFace,
6348
6349
  findFace: findFace,
6349
6350
  findTransitionRegion: findTransitionRegion,
6350
6351
  getTopology: getTopology
@@ -6384,6 +6385,37 @@
6384
6385
  return p;
6385
6386
  }
6386
6387
 
6388
+ function invertFace(x, y, faceId) {
6389
+ var face = faces[faceId];
6390
+ var p, rotated;
6391
+ if (!face || !face.project.invert) return null;
6392
+ p = inverseTransformOutputPoint([x + centerX, y + centerY]);
6393
+ p = applyMatrix$1(invertMatrix$1(face.transform), p);
6394
+ rotated = face.project.invert(p[0], p[1]);
6395
+ if (!rotated) return null;
6396
+ return rotateRadians(
6397
+ rotated[0],
6398
+ rotated[1],
6399
+ config.rotation[0] * D2R$7,
6400
+ config.rotation[1] * D2R$7,
6401
+ config.rotation[2] * D2R$7,
6402
+ true
6403
+ );
6404
+ }
6405
+
6406
+ function inverseTransformOutputPoint(p) {
6407
+ var x = p[0];
6408
+ var y = p[1];
6409
+ if (planarAngle) {
6410
+ var cos = Math.cos(planarAngle);
6411
+ var sin = Math.sin(planarAngle);
6412
+ var x2 = x * cos + y * sin;
6413
+ y = -x * sin + y * cos;
6414
+ x = x2;
6415
+ }
6416
+ return [x / scale, -y / scale];
6417
+ }
6418
+
6387
6419
  function findFace(lam, phi) {
6388
6420
  var rotated = rotateRadians(
6389
6421
  lam,
@@ -6453,7 +6485,7 @@
6453
6485
  );
6454
6486
  return [normalizeLongitude$3(q[0] * R2D$6 + lon0), q[1] * R2D$6];
6455
6487
  });
6456
- var paths = splitPathAtAntimeridian$2(
6488
+ var paths = splitPathAtAntimeridian$3(
6457
6489
  interpolateGreatCircle(endpoints[0], endpoints[1], 0.05)
6458
6490
  );
6459
6491
  paths.forEach(function(path) {
@@ -6722,6 +6754,18 @@
6722
6754
  ];
6723
6755
  }
6724
6756
 
6757
+ function invertMatrix$1(m) {
6758
+ var det = m[0] * m[4] - m[1] * m[3];
6759
+ return [
6760
+ m[4] / det,
6761
+ -m[1] / det,
6762
+ (m[1] * m[5] - m[4] * m[2]) / det,
6763
+ -m[3] / det,
6764
+ m[0] / det,
6765
+ (m[3] * m[2] - m[0] * m[5]) / det
6766
+ ];
6767
+ }
6768
+
6725
6769
  function rotateRadians(lam, phi, deltaLam, deltaPhi, deltaGamma, invert) {
6726
6770
  if (invert) {
6727
6771
  var inv = rotatePhiGamma$1(lam, phi, deltaPhi, deltaGamma, true);
@@ -6747,21 +6791,21 @@
6747
6791
  return [
6748
6792
  Math.atan2(y * cosDeltaGamma + z * sinDeltaGamma,
6749
6793
  x * cosDeltaPhi + k * sinDeltaPhi),
6750
- Math.asin(clamp$3(k * cosDeltaPhi - x * sinDeltaPhi, -1, 1))
6794
+ Math.asin(clamp$4(k * cosDeltaPhi - x * sinDeltaPhi, -1, 1))
6751
6795
  ];
6752
6796
  }
6753
6797
  k = z * cosDeltaPhi + x * sinDeltaPhi;
6754
6798
  return [
6755
6799
  Math.atan2(y * cosDeltaGamma - k * sinDeltaGamma,
6756
6800
  x * cosDeltaPhi - z * sinDeltaPhi),
6757
- Math.asin(clamp$3(k * cosDeltaGamma + y * sinDeltaGamma, -1, 1))
6801
+ Math.asin(clamp$4(k * cosDeltaGamma + y * sinDeltaGamma, -1, 1))
6758
6802
  ];
6759
6803
  }
6760
6804
 
6761
6805
  function interpolateGreatCircle(a, b, interval) {
6762
6806
  var av = degreesToVector$2(a[0], a[1]);
6763
6807
  var bv = degreesToVector$2(b[0], b[1]);
6764
- var angle = Math.acos(clamp$3(dot$2(av, bv), -1, 1));
6808
+ var angle = Math.acos(clamp$4(dot$2(av, bv), -1, 1));
6765
6809
  var n = Math.max(1, Math.ceil(angle * R2D$6 / interval));
6766
6810
  var sinAngle = Math.sin(angle);
6767
6811
  var points = [];
@@ -6784,7 +6828,7 @@
6784
6828
  return points;
6785
6829
  }
6786
6830
 
6787
- function splitPathAtAntimeridian$2(path) {
6831
+ function splitPathAtAntimeridian$3(path) {
6788
6832
  var paths = [];
6789
6833
  var part = [path[0]];
6790
6834
  for (var i = 1; i < path.length; i++) {
@@ -6820,7 +6864,7 @@
6820
6864
  }
6821
6865
 
6822
6866
  function angularDistance(a, b) {
6823
- return Math.acos(clamp$3(dot$2(degreesToVector$2(a[0], a[1]),
6867
+ return Math.acos(clamp$4(dot$2(degreesToVector$2(a[0], a[1]),
6824
6868
  degreesToVector$2(b[0], b[1])), -1, 1));
6825
6869
  }
6826
6870
 
@@ -6836,7 +6880,7 @@
6836
6880
  function vectorToDegrees$2(p) {
6837
6881
  return [
6838
6882
  Math.atan2(p[1], p[0]) * R2D$6,
6839
- Math.asin(clamp$3(p[2], -1, 1)) * R2D$6
6883
+ Math.asin(clamp$4(p[2], -1, 1)) * R2D$6
6840
6884
  ];
6841
6885
  }
6842
6886
 
@@ -6897,7 +6941,7 @@
6897
6941
  return lon;
6898
6942
  }
6899
6943
 
6900
- function clamp$3(val, min, max) {
6944
+ function clamp$4(val, min, max) {
6901
6945
  return Math.max(min, Math.min(max, val));
6902
6946
  }
6903
6947
 
@@ -8618,7 +8662,7 @@
8618
8662
  function interpolateSphericalRadians(a, b, interval) {
8619
8663
  var av = radiansToVector(a[0], a[1]);
8620
8664
  var bv = radiansToVector(b[0], b[1]);
8621
- var angle = Math.acos(clamp$2(dot$1(av, bv), -1, 1));
8665
+ var angle = Math.acos(clamp$3(dot$1(av, bv), -1, 1));
8622
8666
  var count = Math.max(1, Math.ceil(angle / interval));
8623
8667
  var sinAngle = Math.sin(angle);
8624
8668
  var points = [];
@@ -8638,7 +8682,7 @@
8638
8682
  function vectorToRadians(p) {
8639
8683
  return [
8640
8684
  Math.atan2(p[1], p[0]),
8641
- Math.asin(clamp$2(p[2], -1, 1))
8685
+ Math.asin(clamp$3(p[2], -1, 1))
8642
8686
  ];
8643
8687
  }
8644
8688
 
@@ -8712,8 +8756,8 @@
8712
8756
  }
8713
8757
  x = qx - BLOCK_HEIGHT;
8714
8758
  y = qy + 1.5;
8715
- x = clamp$2(x, XMIN, XMAX);
8716
- y = clamp$2(y, YMIN, YMAX);
8759
+ x = clamp$3(x, XMIN, XMAX);
8760
+ y = clamp$3(y, YMIN, YMAX);
8717
8761
  return {
8718
8762
  x: x,
8719
8763
  y: y,
@@ -8823,7 +8867,7 @@
8823
8867
  var v = radiansToVector(lam, phi);
8824
8868
  return [
8825
8869
  Math.atan2(dot$1(v, orientation.y), dot$1(v, orientation.x)),
8826
- Math.asin(clamp$2(dot$1(v, orientation.z), -1, 1))
8870
+ Math.asin(clamp$3(dot$1(v, orientation.z), -1, 1))
8827
8871
  ];
8828
8872
  }
8829
8873
 
@@ -8834,7 +8878,7 @@
8834
8878
  orientation.x[1] * v[0] + orientation.y[1] * v[1] + orientation.z[1] * v[2],
8835
8879
  orientation.x[2] * v[0] + orientation.y[2] * v[1] + orientation.z[2] * v[2]
8836
8880
  ];
8837
- return [Math.atan2(p[1], p[0]), Math.asin(clamp$2(p[2], -1, 1))];
8881
+ return [Math.atan2(p[1], p[0]), Math.asin(clamp$3(p[2], -1, 1))];
8838
8882
  }
8839
8883
 
8840
8884
  // Adapted from Justin Kunimune's Imago implementation.
@@ -8848,7 +8892,7 @@
8848
8892
  lat1 = lat;
8849
8893
  lon1 = lon - lon0;
8850
8894
  } else {
8851
- lat1 = Math.asin(clamp$2(
8895
+ lat1 = Math.asin(clamp$3(
8852
8896
  Math.sin(lat0) * Math.sin(lat) +
8853
8897
  Math.cos(lat0) * Math.cos(lat) * Math.cos(lon0 - lon),
8854
8898
  -1,
@@ -8859,7 +8903,7 @@
8859
8903
  (Math.cos(lat0) * Math.sin(lat) -
8860
8904
  Math.sin(lat0) * Math.cos(lat) * Math.cos(lon0 - lon)) /
8861
8905
  denominator;
8862
- lon1 = Math.acos(clamp$2(value, -1, 1)) - Math.PI;
8906
+ lon1 = Math.acos(clamp$3(value, -1, 1)) - Math.PI;
8863
8907
  if (Math.sin(lon - lon0) > 0) lon1 = -lon1;
8864
8908
  }
8865
8909
  return [lat1, normalizeRadians(lon1 - theta0)];
@@ -8869,7 +8913,7 @@
8869
8913
  var lat0 = pole.lat;
8870
8914
  var lon0 = pole.lon;
8871
8915
  lon += pole.meridian;
8872
- var latOut = Math.asin(clamp$2(
8916
+ var latOut = Math.asin(clamp$3(
8873
8917
  Math.sin(lat0) * Math.sin(lat) -
8874
8918
  Math.cos(lat0) * Math.cos(lon) * Math.cos(lat),
8875
8919
  -1,
@@ -8881,8 +8925,8 @@
8881
8925
  } else {
8882
8926
  var value = Math.sin(lat) / Math.cos(lat0) / Math.cos(latOut) -
8883
8927
  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));
8928
+ if (Math.sin(lon) > 0) lonOut = lon0 + Math.acos(clamp$3(value, -1, 1));
8929
+ else lonOut = lon0 - Math.acos(clamp$3(value, -1, 1));
8886
8930
  }
8887
8931
  return [latOut, normalizeRadians(lonOut)];
8888
8932
  }
@@ -8909,7 +8953,7 @@
8909
8953
  p[1] * R2D$2
8910
8954
  ]);
8911
8955
  }
8912
- return memo.concat(splitPathAtAntimeridian$1(path));
8956
+ return memo.concat(splitPathAtAntimeridian$2(path));
8913
8957
  }, []);
8914
8958
  return paths.map(function(part) {
8915
8959
  part.mask_width = 4e-5;
@@ -8917,7 +8961,7 @@
8917
8961
  });
8918
8962
  }
8919
8963
 
8920
- function splitPathAtAntimeridian$1(path) {
8964
+ function splitPathAtAntimeridian$2(path) {
8921
8965
  var paths = [];
8922
8966
  var part = [path[0]];
8923
8967
  for (var i = 1; i < path.length; i++) {
@@ -9002,7 +9046,7 @@
9002
9046
  return lon;
9003
9047
  }
9004
9048
 
9005
- function clamp$2(value, min, max) {
9049
+ function clamp$3(value, min, max) {
9006
9050
  return Math.max(min, Math.min(max, value));
9007
9051
  }
9008
9052
 
@@ -9033,11 +9077,15 @@
9033
9077
  var SQRT3 = Math.sqrt(3);
9034
9078
  var ASIN_ONE_THIRD = Math.asin(1 / 3);
9035
9079
  var MARKLEY_LATITUDE = Math.acos(1 / 3) * 0.5 * R2D$1;
9080
+ var LAYOUT_PERIOD = 8;
9081
+ var MARKLEY_LAYOUT_PHASE = -2;
9082
+ var CALM_LAYOUT_PHASE = -1.5;
9036
9083
  var RECT_XMIN = -7;
9037
9084
  var RECT_XMAX = 1;
9038
9085
  var RECT_YMIN = -2 * SQRT3;
9039
9086
  var RECT_YMAX = 0;
9040
9087
  var EPS = 1e-12;
9088
+ var MIN_PIECE_AREA = 1e-6;
9041
9089
  var engines = {};
9042
9090
 
9043
9091
  var TETRAHEDRON_VERTICES = [
@@ -9081,7 +9129,10 @@
9081
9129
  function getLeeTetrahedralEngine(id) {
9082
9130
  id = id || 'markley';
9083
9131
  if (!engines[id]) {
9084
- engines[id] = createLeeTetrahedralEngine(getProjectionRotation(id));
9132
+ engines[id] = createLeeTetrahedralEngine(
9133
+ getProjectionRotation(id),
9134
+ id == 'markley' ? MARKLEY_LAYOUT_PHASE : CALM_LAYOUT_PHASE
9135
+ );
9085
9136
  }
9086
9137
  return engines[id];
9087
9138
  }
@@ -9097,23 +9148,24 @@
9097
9148
  };
9098
9149
  P.__projection_topology = engine.getTopology(P.lam0 * R2D$1);
9099
9150
  P.__projected_outline = engine.outline;
9151
+ P.__graticule_precision = 1;
9100
9152
  }
9101
9153
 
9102
9154
  function getProjectionRotation(id) {
9103
9155
  if (id == 'calm') {
9104
- // Exact D3 Euler equivalent of MapDesigner's published CALM aspect:
9105
- // latitude 77°, longitude 143°, central meridian -163°.
9156
+ // Kunimune's published CALM aspect (77°N, 143°E, central meridian
9157
+ // 163°W), transformed into this implementation's tetrahedral symmetry.
9106
9158
  return [
9107
- 19.57956907750618,
9108
- -12.42267097553935,
9109
- 3.8615690020132067
9159
+ 64.7261399569101,
9160
+ -39.84470062116125,
9161
+ -119.02303523591051
9110
9162
  ];
9111
9163
  }
9112
9164
  // Markley's singularities are at ±35.26439°, in the oceans.
9113
9165
  return [115, MARKLEY_LATITUDE - 90, 180];
9114
9166
  }
9115
9167
 
9116
- function createLeeTetrahedralEngine(rotation) {
9168
+ function createLeeTetrahedralEngine(rotation, layoutPhase) {
9117
9169
  var base = createPolyhedralProjection({
9118
9170
  faces: TETRAHEDRON_FACES,
9119
9171
  parents: [-1, 0, 0, 0],
@@ -9124,10 +9176,11 @@
9124
9176
  var normalization = getBaseNormalization(base.outline);
9125
9177
  var baseTopology = base.getTopology(0);
9126
9178
  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
- }));
9179
+ var rasterPieces = createLayoutPieces(
9180
+ baseTopology.regions, normalization, layoutPhase);
9181
+ var rasterPieceIndex = indexPiecesByFaceAndCopy(rasterPieces);
9182
+ var rasterPieceIds = rasterPieces.map(function(piece) { return piece.id; });
9183
+ var seamCache = new Map();
9131
9184
  var outline = [[
9132
9185
  centerOutputPoint([RECT_XMIN, RECT_YMIN]),
9133
9186
  centerOutputPoint([RECT_XMAX, RECT_YMIN]),
@@ -9138,6 +9191,7 @@
9138
9191
 
9139
9192
  return {
9140
9193
  forward: forward,
9194
+ inverse: inverse,
9141
9195
  outline: outline,
9142
9196
  getTopology: getTopology
9143
9197
  };
@@ -9145,24 +9199,42 @@
9145
9199
  function forward(lam, phi) {
9146
9200
  var p = normalizeBasePoint(base.forward(lam, phi), normalization);
9147
9201
  var copy = getLayoutCopy(p);
9148
- return centerOutputPoint(applyMatrix(copy.matrix, p));
9202
+ var q = applyMatrix(copy.matrix, p);
9203
+ q[0] = wrapLayoutX(q[0] + layoutPhase);
9204
+ q[0] = clamp$2(q[0], RECT_XMIN, RECT_XMAX);
9205
+ q[1] = clamp$2(q[1], RECT_YMIN, RECT_YMAX);
9206
+ return centerOutputPoint(q);
9207
+ }
9208
+
9209
+ // Internal inverse used to trace the geographic cut corresponding to the
9210
+ // rectangular frame. The public projection remains forward-only.
9211
+ function inverse(x, y) {
9212
+ var q = uncenterOutputPoint([x, y]);
9213
+ for (var i = 0; i < rasterPieces.length; i++) {
9214
+ var piece = rasterPieces[i];
9215
+ if (!pointInRing$2(centerOutputPoint(q), piece.boundary)) continue;
9216
+ var p = applyMatrix(invertMatrix(piece.matrix), q);
9217
+ var projected = getLayoutCopy(p);
9218
+ if (projected.id != piece.copy) continue;
9219
+ p = denormalizeBasePoint(p, normalization);
9220
+ var spherical = base.invertFace(p[0], p[1], piece.face);
9221
+ if (!spherical) continue;
9222
+ var check = forward(spherical[0], spherical[1]);
9223
+ if (Math.hypot(check[0] - x, check[1] - y) < 1e-6) {
9224
+ return spherical;
9225
+ }
9226
+ }
9227
+ return null;
9149
9228
  }
9150
9229
 
9151
9230
  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
- }),
9231
+ var result = {
9232
+ interrupted: true,
9233
+ regions: rasterPieces.map(copyProjectedPiece),
9162
9234
  findRegion: findRegion,
9163
9235
  findTransitionRegion: findRegion,
9164
9236
  projectRegion: projectRegion,
9165
- raster_regions: pieces.map(copyRasterPiece),
9237
+ raster_regions: rasterPieces.map(copyRasterPiece),
9166
9238
  raster_source_regions: sourceRegions.map(function(region) {
9167
9239
  return {
9168
9240
  id: region.id,
@@ -9178,14 +9250,44 @@
9178
9250
  raster_cell_halo: false,
9179
9251
  fill_raster_mask: true,
9180
9252
  fill_raster_coverage: true,
9181
- findRasterRegion: findRegion,
9182
- projectRasterRegion: projectRegion,
9253
+ findRasterRegion: findRasterRegion,
9254
+ projectRasterRegion: projectRasterRegion,
9183
9255
  projectRasterSourceRegion: projectRasterSourceRegion,
9184
9256
  clipRasterRegionPolygon: clipRasterRegionPolygon,
9257
+ frame_bounds: [
9258
+ outline[0][0][0],
9259
+ outline[0][0][1],
9260
+ outline[0][2][0],
9261
+ outline[0][2][1]
9262
+ ],
9185
9263
  outline: outline.map(function(ring) {
9186
9264
  return ring.map(function(p) { return p.concat(); });
9187
9265
  })
9188
9266
  };
9267
+ // Rasters use the region mesh but never need geographic seam paths.
9268
+ // Tracing the rectangular cut is deferred until vector clipping requests it.
9269
+ Object.defineProperty(result, 'seams', {
9270
+ enumerable: true,
9271
+ get: function() {
9272
+ if (!seamCache.has(lon0)) {
9273
+ var topology = base.getTopology(lon0);
9274
+ var seams = topology.seams.map(function(seam) {
9275
+ return {
9276
+ type: 'attached',
9277
+ faces: seam.faces,
9278
+ paths: seam.paths
9279
+ };
9280
+ });
9281
+ seams.push({
9282
+ type: 'cut',
9283
+ paths: createFrameCutPaths(inverse, lon0)
9284
+ });
9285
+ seamCache.set(lon0, seams);
9286
+ }
9287
+ return seamCache.get(lon0);
9288
+ }
9289
+ });
9290
+ return result;
9189
9291
 
9190
9292
  function findRegion(lon, lat) {
9191
9293
  var lam = normalizeLongitude$1(lon - lon0) * D2R$1;
@@ -9193,11 +9295,32 @@
9193
9295
  var face = base.findFace(lam, phi);
9194
9296
  var p = normalizeBasePoint(base.forwardFace(lam, phi, face), normalization);
9195
9297
  var copy = getLayoutCopy(p);
9196
- return pieceIndex.get(getPieceKey(face, copy.id));
9298
+ var q = applyMatrix(copy.matrix, p);
9299
+ q[0] = wrapLayoutX(q[0] + layoutPhase);
9300
+ q[0] = clamp$2(q[0], RECT_XMIN, RECT_XMAX);
9301
+ q[1] = clamp$2(q[1], RECT_YMIN, RECT_YMAX);
9302
+ q = centerOutputPoint(q);
9303
+ var ids = rasterPieceIndex.get(getPieceKey(face, copy.id)) || [];
9304
+ var region = findPieceContainingPoint(rasterPieces, ids, q);
9305
+ if (region === undefined) {
9306
+ region = findPieceContainingPoint(rasterPieces, rasterPieceIds, q);
9307
+ }
9308
+ return region;
9197
9309
  }
9198
9310
 
9199
9311
  function projectRegion(lon, lat, regionId) {
9200
- var piece = pieces[regionId];
9312
+ return projectPiece(lon, lat, rasterPieces[regionId]);
9313
+ }
9314
+
9315
+ function findRasterRegion(lon, lat) {
9316
+ return findRegion(lon, lat);
9317
+ }
9318
+
9319
+ function projectRasterRegion(lon, lat, regionId) {
9320
+ return projectPiece(lon, lat, rasterPieces[regionId]);
9321
+ }
9322
+
9323
+ function projectPiece(lon, lat, piece) {
9201
9324
  var lam = normalizeLongitude$1(lon - lon0) * D2R$1;
9202
9325
  var p = normalizeBasePoint(
9203
9326
  base.forwardFace(lam, lat * D2R$1, piece.face),
@@ -9215,7 +9338,7 @@
9215
9338
  }
9216
9339
 
9217
9340
  function clipRasterRegionPolygon(vertices, regionId) {
9218
- var piece = pieces[regionId];
9341
+ var piece = rasterPieces[regionId];
9219
9342
  var polygon = vertices.map(function(vertex) {
9220
9343
  var p = applyMatrix(piece.matrix, [vertex.x, vertex.y]);
9221
9344
  return copyRasterVertex(vertex, p[0], p[1]);
@@ -9246,39 +9369,63 @@
9246
9369
  });
9247
9370
  }
9248
9371
 
9249
- function createLayoutPieces(regions, normalization) {
9372
+ function createLayoutPieces(regions, normalization, layoutPhase) {
9250
9373
  var pieces = [];
9251
9374
  regions.forEach(function(region) {
9252
9375
  var boundary = region.projected_boundary.map(function(p) {
9253
9376
  return normalizeBasePoint(p, normalization);
9254
9377
  });
9255
9378
  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)
9379
+ var polygon = clipLayoutCopyDomain(boundary, copy.id);
9380
+ if (polygon.length < 3 ||
9381
+ Math.abs(getRingArea$2(polygon)) < MIN_PIECE_AREA) return;
9382
+ [-LAYOUT_PERIOD, 0, LAYOUT_PERIOD].forEach(function(wrap) {
9383
+ var matrix = shiftMatrixX(copy.matrix, layoutPhase + wrap);
9384
+ var projected = polygon.map(function(p) {
9385
+ return applyMatrix(matrix, p);
9386
+ });
9387
+ projected = clipPolygonAxis(projected, 0, RECT_XMIN, true);
9388
+ projected = clipPolygonAxis(projected, 0, RECT_XMAX, false);
9389
+ projected = clipPolygonAxis(projected, 1, RECT_YMIN, true);
9390
+ projected = clipPolygonAxis(projected, 1, RECT_YMAX, false);
9391
+ if (projected.length < 3 ||
9392
+ Math.abs(getRingArea$2(projected)) < MIN_PIECE_AREA) return;
9393
+ pieces.push({
9394
+ id: pieces.length,
9395
+ face: region.id,
9396
+ source_region: region.id,
9397
+ copy: copy.id,
9398
+ matrix: matrix,
9399
+ boundary: projected.map(centerOutputPoint)
9400
+ });
9272
9401
  });
9273
9402
  });
9274
9403
  });
9275
9404
  return pieces;
9276
9405
  }
9277
9406
 
9407
+ function clipLayoutCopyDomain(polygon, copyId) {
9408
+ if (copyId == 0) { // green
9409
+ polygon = clipPolygonAxis(polygon, 1, 0, true);
9410
+ polygon = clipPolygonAxis(polygon, 0, 3, false);
9411
+ } else if (copyId == 2) { // blue
9412
+ polygon = clipPolygonAxis(polygon, 1, 0, true);
9413
+ polygon = clipPolygonAxis(polygon, 0, 3, true);
9414
+ } else if (copyId == 1) { // red
9415
+ polygon = clipPolygonAxis(polygon, 1, 0, false);
9416
+ polygon = clipPolygonAxis(polygon, 0, 1, false);
9417
+ } else { // orange
9418
+ polygon = clipPolygonAxis(polygon, 1, 0, false);
9419
+ polygon = clipPolygonAxis(polygon, 0, 1, true);
9420
+ }
9421
+ return polygon;
9422
+ }
9423
+
9278
9424
  function copyProjectedPiece(piece) {
9279
9425
  return {
9280
9426
  id: piece.id,
9281
9427
  source_region: piece.source_region,
9428
+ copy: piece.copy,
9282
9429
  projected_boundary: closeRing$1(piece.boundary)
9283
9430
  };
9284
9431
  }
@@ -9291,9 +9438,68 @@
9291
9438
  };
9292
9439
  }
9293
9440
 
9441
+ function createFrameCutPaths(inverse, lon0) {
9442
+ // The repeated tetrahedral net is continuous inside the frame. Its only
9443
+ // geographic cuts are the three independent sides of the periodic rectangle.
9444
+ var n = 6000;
9445
+ // Stay far enough inside the frame to avoid browser-specific inverse
9446
+ // branches at the exact Lee face boundary.
9447
+ var epsilon = 5e-8;
9448
+ var xmin = centerOutputPoint([RECT_XMIN, 0])[0];
9449
+ var xmax = centerOutputPoint([RECT_XMAX, 0])[0];
9450
+ var ymin = centerOutputPoint([0, RECT_YMIN])[1];
9451
+ var ymax = centerOutputPoint([0, RECT_YMAX])[1];
9452
+ var edges = [
9453
+ [[xmin + epsilon, ymin], [xmin + epsilon, ymax]],
9454
+ [[xmin, ymax - epsilon], [xmax, ymax - epsilon]],
9455
+ [[xmin, ymin + epsilon], [xmax, ymin + epsilon]]
9456
+ ];
9457
+ return edges.reduce(function(memo, edge) {
9458
+ var path = [];
9459
+ for (var i = 0; i <= n; i++) {
9460
+ var t = i / n;
9461
+ var x = edge[0][0] + (edge[1][0] - edge[0][0]) * t;
9462
+ var y = edge[0][1] + (edge[1][1] - edge[0][1]) * t;
9463
+ var p = inverse(x, y);
9464
+ if (!p) continue;
9465
+ path.push([
9466
+ normalizeLongitude$1(p[0] * R2D$1 + lon0),
9467
+ p[1] * R2D$1
9468
+ ]);
9469
+ }
9470
+ return memo.concat(splitPathAtAntimeridian$1(path));
9471
+ }, []).map(function(path) {
9472
+ path.mask_width = 4e-5;
9473
+ return path;
9474
+ });
9475
+ }
9476
+
9477
+ function splitPathAtAntimeridian$1(path) {
9478
+ if (path.length < 2) return [];
9479
+ var paths = [];
9480
+ var part = [path[0]];
9481
+ for (var i = 1; i < path.length; i++) {
9482
+ var a = path[i - 1];
9483
+ var b = path[i];
9484
+ if (Math.abs(a[0] - b[0]) > 180) {
9485
+ var adjusted = b[0] + (b[0] < a[0] ? 360 : -360);
9486
+ var edge = a[0] < 0 ? -180 : 180;
9487
+ var t = (edge - a[0]) / (adjusted - a[0]);
9488
+ var lat = a[1] + (b[1] - a[1]) * t;
9489
+ part.push([edge, lat]);
9490
+ paths.push(part);
9491
+ part = [[-edge, lat], b];
9492
+ } else {
9493
+ part.push(b);
9494
+ }
9495
+ }
9496
+ if (part.length > 1) paths.push(part);
9497
+ return paths;
9498
+ }
9499
+
9294
9500
  function closeRing$1(ring) {
9295
9501
  var copy = ring.map(function(p) { return p.concat(); });
9296
- if (copy.length && !pointsEqual$1(copy[0], copy[copy.length - 1])) {
9502
+ if (copy.length && !pointsEqual$2(copy[0], copy[copy.length - 1])) {
9297
9503
  copy.push(copy[0].concat());
9298
9504
  }
9299
9505
  return copy;
@@ -9313,6 +9519,13 @@
9313
9519
  ];
9314
9520
  }
9315
9521
 
9522
+ function uncenterOutputPoint(p) {
9523
+ return [
9524
+ p[0] + (RECT_XMIN + RECT_XMAX) / 2,
9525
+ p[1] + (RECT_YMIN + RECT_YMAX) / 2
9526
+ ];
9527
+ }
9528
+
9316
9529
  function getBaseNormalization(outline) {
9317
9530
  var xmin = Infinity;
9318
9531
  var ymin = Infinity;
@@ -9340,16 +9553,28 @@
9340
9553
  ];
9341
9554
  }
9342
9555
 
9556
+ function denormalizeBasePoint(p, normalization) {
9557
+ return [
9558
+ p[0] / normalization.scale + normalization.cx,
9559
+ -p[1] / normalization.scale + normalization.cy
9560
+ ];
9561
+ }
9562
+
9343
9563
  function createLeeFaceProjector(face) {
9344
9564
  var c = face.centroid;
9345
9565
  var rotation = Math.abs(c[1]) == 90 ?
9346
9566
  [0, -c[1], -30] :
9347
9567
  [-c[0], -c[1], 30];
9348
- return function(lam, phi) {
9568
+ function project(lam, phi) {
9349
9569
  var p = rotateSphericalRadians(lam, phi, rotation);
9350
9570
  var q = leeRaw(p[0], p[1]);
9351
9571
  return [q[0], -q[1]];
9572
+ }
9573
+ project.invert = function(x, y) {
9574
+ var p = invertLeeRaw(x, -y);
9575
+ return p && rotateSphericalRadians(p[0], p[1], rotation, true);
9352
9576
  };
9577
+ return project;
9353
9578
  }
9354
9579
 
9355
9580
  function leeRaw(lam, phi) {
@@ -9408,6 +9633,47 @@
9408
9633
  );
9409
9634
  }
9410
9635
 
9636
+ function invertLeeRaw(x, y) {
9637
+ var lam = x;
9638
+ var phi = y * 0.5;
9639
+ var da = 0;
9640
+ var db = 0;
9641
+ var err2 = Infinity;
9642
+ var eps = 1e-12;
9643
+ for (var i = 0; i < 40; i++) {
9644
+ var q = leeRaw(lam, phi);
9645
+ var tx = q[0] - x;
9646
+ var ty = q[1] - y;
9647
+ if (Math.abs(tx) < eps && Math.abs(ty) < eps) break;
9648
+ var error = tx * tx + ty * ty;
9649
+ if (error > err2) {
9650
+ lam -= da /= 2;
9651
+ phi -= db /= 2;
9652
+ continue;
9653
+ }
9654
+ err2 = error;
9655
+ var ea = (lam > 0 ? -1 : 1) * eps;
9656
+ var eb = (phi > 0 ? -1 : 1) * eps;
9657
+ var qa = leeRaw(lam + ea, phi);
9658
+ var qb = leeRaw(lam, phi + eb);
9659
+ var dxa = (qa[0] - q[0]) / ea;
9660
+ var dya = (qa[1] - q[1]) / ea;
9661
+ var dxb = (qb[0] - q[0]) / eb;
9662
+ var dyb = (qb[1] - q[1]) / eb;
9663
+ var det = dyb * dxa - dya * dxb;
9664
+ if (Math.abs(det) < 1e-14) break;
9665
+ var scale = (Math.abs(det) < 0.5 ? 0.5 : 1) / det;
9666
+ da = (ty * dxb - tx * dyb) * scale;
9667
+ db = (tx * dya - ty * dxa) * scale;
9668
+ lam += da;
9669
+ phi += db;
9670
+ if (Math.abs(da) < eps && Math.abs(db) < eps) break;
9671
+ }
9672
+ var check = leeRaw(lam, phi);
9673
+ return Math.hypot(check[0] - x, check[1] - y) < 1e-8 ?
9674
+ [lam, phi] : null;
9675
+ }
9676
+
9411
9677
  function stereographicRaw(lam, phi) {
9412
9678
  var cosPhi = Math.cos(phi);
9413
9679
  var k = 1 / (1 + cosPhi * Math.cos(lam));
@@ -9452,6 +9718,30 @@
9452
9718
  ];
9453
9719
  }
9454
9720
 
9721
+ function shiftMatrixX(matrix, offset) {
9722
+ var shifted = matrix.concat();
9723
+ shifted[2] += offset;
9724
+ return shifted;
9725
+ }
9726
+
9727
+ function wrapLayoutX(x) {
9728
+ while (x < RECT_XMIN) x += LAYOUT_PERIOD;
9729
+ while (x > RECT_XMAX) x -= LAYOUT_PERIOD;
9730
+ return x;
9731
+ }
9732
+
9733
+ function invertMatrix(m) {
9734
+ var det = m[0] * m[4] - m[1] * m[3];
9735
+ return [
9736
+ m[4] / det,
9737
+ -m[1] / det,
9738
+ (m[1] * m[5] - m[4] * m[2]) / det,
9739
+ -m[3] / det,
9740
+ m[0] / det,
9741
+ (m[3] * m[2] - m[0] * m[5]) / det
9742
+ ];
9743
+ }
9744
+
9455
9745
  function clipPolygonAxis(polygon, axis, value, keepGreater) {
9456
9746
  var output = [];
9457
9747
  if (!polygon.length) return output;
@@ -9528,11 +9818,48 @@
9528
9818
  return area / 2;
9529
9819
  }
9530
9820
 
9821
+ function indexPiecesByFaceAndCopy(pieces) {
9822
+ var index = new Map();
9823
+ pieces.forEach(function(piece) {
9824
+ var key = getPieceKey(piece.face, piece.copy);
9825
+ if (!index.has(key)) index.set(key, []);
9826
+ index.get(key).push(piece.id);
9827
+ });
9828
+ return index;
9829
+ }
9830
+
9831
+ function findPieceContainingPoint(pieces, ids, point) {
9832
+ for (var i = 0; i < ids.length; i++) {
9833
+ if (pointInRing$2(point, pieces[ids[i]].boundary)) return ids[i];
9834
+ }
9835
+ }
9836
+
9837
+ function pointInRing$2(point, ring) {
9838
+ var inside = false;
9839
+ for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) {
9840
+ var a = ring[j];
9841
+ var b = ring[i];
9842
+ var cross = (point[0] - a[0]) * (b[1] - a[1]) -
9843
+ (point[1] - a[1]) * (b[0] - a[0]);
9844
+ if (Math.abs(cross) < 1e-8 &&
9845
+ point[0] >= Math.min(a[0], b[0]) - 1e-8 &&
9846
+ point[0] <= Math.max(a[0], b[0]) + 1e-8 &&
9847
+ point[1] >= Math.min(a[1], b[1]) - 1e-8 &&
9848
+ point[1] <= Math.max(a[1], b[1]) + 1e-8) return true;
9849
+ if ((a[1] > point[1]) != (b[1] > point[1]) &&
9850
+ point[0] < (b[0] - a[0]) * (point[1] - a[1]) /
9851
+ (b[1] - a[1]) + a[0]) {
9852
+ inside = !inside;
9853
+ }
9854
+ }
9855
+ return inside;
9856
+ }
9857
+
9531
9858
  function getPieceKey(face, copy) {
9532
9859
  return face + ':' + copy;
9533
9860
  }
9534
9861
 
9535
- function pointsEqual$1(a, b) {
9862
+ function pointsEqual$2(a, b) {
9536
9863
  return Math.abs(a[0] - b[0]) < EPS && Math.abs(a[1] - b[1]) < EPS;
9537
9864
  }
9538
9865
 
@@ -9542,6 +9869,10 @@
9542
9869
  return lon - 180;
9543
9870
  }
9544
9871
 
9872
+ function clamp$2(value, min, max) {
9873
+ return Math.max(min, Math.min(max, value));
9874
+ }
9875
+
9545
9876
  var mproj$1 = require$1('mproj');
9546
9877
  registerDymaxionProjections(mproj$1);
9547
9878
  registerButterflyProjections(mproj$1);
@@ -41966,10 +42297,10 @@ ${svg}
41966
42297
  var coords = path.coords;
41967
42298
  if (coords.length < 2) return;
41968
42299
  if (forcePolylinePaths) {
41969
- lines.push(path.closed || pointsEqual(coords[0], coords[coords.length - 1]) ? closeRing(coords) : coords);
42300
+ lines.push(path.closed || pointsEqual$1(coords[0], coords[coords.length - 1]) ? closeRing(coords) : coords);
41970
42301
  return;
41971
42302
  }
41972
- if (path.closed || pointsEqual(coords[0], coords[coords.length - 1])) {
42303
+ if (path.closed || pointsEqual$1(coords[0], coords[coords.length - 1])) {
41973
42304
  if (coords.length >= 3) {
41974
42305
  rings.push(closeRing(coords));
41975
42306
  }
@@ -42192,7 +42523,7 @@ ${svg}
42192
42523
  for (var i = 0; i < subpaths.length; i++) {
42193
42524
  var coords = subpaths[i].coords;
42194
42525
  if (coords.length < 2) continue;
42195
- if (!subpaths[i].closed && !pointsEqual(coords[0], coords[coords.length - 1])) {
42526
+ if (!subpaths[i].closed && !pointsEqual$1(coords[0], coords[coords.length - 1])) {
42196
42527
  return true;
42197
42528
  }
42198
42529
  }
@@ -42277,7 +42608,7 @@ ${svg}
42277
42608
 
42278
42609
  function closeRing(coords) {
42279
42610
  var ring = coords.map(function(p) { return [p[0], p[1]]; });
42280
- if (!pointsEqual(ring[0], ring[ring.length - 1])) {
42611
+ if (!pointsEqual$1(ring[0], ring[ring.length - 1])) {
42281
42612
  ring.push([ring[0][0], ring[0][1]]);
42282
42613
  }
42283
42614
  return ring;
@@ -42332,7 +42663,7 @@ ${svg}
42332
42663
  return /^[a-z]$/i.test(token);
42333
42664
  }
42334
42665
 
42335
- function pointsEqual(a, b) {
42666
+ function pointsEqual$1(a, b) {
42336
42667
  return a && b && a[0] == b[0] && a[1] == b[1];
42337
42668
  }
42338
42669
 
@@ -55898,6 +56229,9 @@ ${svg}
55898
56229
 
55899
56230
  function isInterruptedProjection(P) {
55900
56231
  if (P && P.__projection_topology) {
56232
+ if (P.__projection_topology.interrupted !== undefined) {
56233
+ return P.__projection_topology.interrupted;
56234
+ }
55901
56235
  return P.__projection_topology.seams.some(function(o) {
55902
56236
  return o.type == 'cut';
55903
56237
  });
@@ -57956,6 +58290,120 @@ ${svg}
57956
58290
  projectRasterGridForward: projectRasterGridForward
57957
58291
  });
57958
58292
 
58293
+ function splitPolygonFrameChords(dataset, bounds) {
58294
+ var editor = new DatasetEditor(dataset);
58295
+ dataset.layers.forEach(function(lyr) {
58296
+ if (lyr.geometry_type == 'polygon') {
58297
+ editor.editLayer(lyr, function(path) {
58298
+ return splitRingAtFrameChords(path, bounds);
58299
+ });
58300
+ } else {
58301
+ editor.editLayer(lyr, function(geometry) {
58302
+ return lyr.geometry_type == 'point' ? geometry : [geometry];
58303
+ });
58304
+ }
58305
+ });
58306
+ editor.done();
58307
+ }
58308
+
58309
+ function splitRingAtFrameChords(path, bounds, depth) {
58310
+ depth = depth || 0;
58311
+ var closed = pointsEqual(path[0], path[path.length - 1]);
58312
+ var n = path.length - (closed ? 1 : 0);
58313
+ if (n < 4) return [path];
58314
+ var width = bounds[2] - bounds[0];
58315
+ var height = bounds[3] - bounds[1];
58316
+ var tolerance = Math.max(width, height) * 1e-3;
58317
+ var edgesBySide = [[], [], [], []];
58318
+ for (var i = 0; i < n; i++) {
58319
+ var side = getFrameSide(
58320
+ path[i], path[(i + 1) % n], bounds, tolerance);
58321
+ if (side >= 0) edgesBySide[side].push({index: i, side: side});
58322
+ }
58323
+ for (var frameSide = 0; frameSide < edgesBySide.length; frameSide++) {
58324
+ var runs = groupEdgeRuns(edgesBySide[frameSide], n);
58325
+ if (runs.length > 1) {
58326
+ var parts = splitRingAtRuns(path, n, runs, frameSide, bounds);
58327
+ if (depth >= 3) return parts;
58328
+ return parts.reduce(function(memo, part) {
58329
+ return memo.concat(splitRingAtFrameChords(part, bounds, depth + 1));
58330
+ }, []);
58331
+ }
58332
+ }
58333
+ return [path];
58334
+ }
58335
+
58336
+ function splitRingAtRuns(path, n, runs, side, bounds) {
58337
+ return runs.map(function(run, i) {
58338
+ var next = runs[(i + 1) % runs.length];
58339
+ var start = (run.end + 1) % n;
58340
+ var end = next.start;
58341
+ var part = [];
58342
+ var j = start;
58343
+ while (true) {
58344
+ part.push(path[j].concat());
58345
+ if (j == end) break;
58346
+ j = (j + 1) % n;
58347
+ }
58348
+ if (side == 0 || side == 2) {
58349
+ var y = side == 0 ? bounds[1] : bounds[3];
58350
+ part[0][1] = y;
58351
+ part[part.length - 1][1] = y;
58352
+ } else {
58353
+ var x = side == 1 ? bounds[2] : bounds[0];
58354
+ part[0][0] = x;
58355
+ part[part.length - 1][0] = x;
58356
+ }
58357
+ part.push(part[0].concat());
58358
+ return part;
58359
+ }).filter(function(part) {
58360
+ return part.length > 3;
58361
+ });
58362
+ }
58363
+
58364
+ function getFrameSide(a, b, bounds, tolerance) {
58365
+ var dx = Math.abs(a[0] - b[0]);
58366
+ var dy = Math.abs(a[1] - b[1]);
58367
+ var width = bounds[2] - bounds[0];
58368
+ var height = bounds[3] - bounds[1];
58369
+ if (dx > width * 0.2) {
58370
+ if (Math.abs(a[1] - bounds[1]) < tolerance &&
58371
+ Math.abs(b[1] - bounds[1]) < tolerance) return 0;
58372
+ if (Math.abs(a[1] - bounds[3]) < tolerance &&
58373
+ Math.abs(b[1] - bounds[3]) < tolerance) return 2;
58374
+ }
58375
+ if (dy > height * 0.2) {
58376
+ if (Math.abs(a[0] - bounds[2]) < tolerance &&
58377
+ Math.abs(b[0] - bounds[2]) < tolerance) return 1;
58378
+ if (Math.abs(a[0] - bounds[0]) < tolerance &&
58379
+ Math.abs(b[0] - bounds[0]) < tolerance) return 3;
58380
+ }
58381
+ return -1;
58382
+ }
58383
+
58384
+ function groupEdgeRuns(edges, n) {
58385
+ var runs = [];
58386
+ edges.forEach(function(edge) {
58387
+ var run = runs[runs.length - 1];
58388
+ if (run && edge.side == run.side && edge.index == run.end + 1) {
58389
+ run.end = edge.index;
58390
+ } else {
58391
+ runs.push({start: edge.index, end: edge.index, side: edge.side});
58392
+ }
58393
+ });
58394
+ if (runs.length > 1 && runs[0].start == 0 &&
58395
+ runs[runs.length - 1].end == n - 1 &&
58396
+ runs[0].side == runs[runs.length - 1].side) {
58397
+ runs[0].start = runs[runs.length - 1].start;
58398
+ runs.pop();
58399
+ }
58400
+ return runs;
58401
+ }
58402
+
58403
+ function pointsEqual(a, b) {
58404
+ return a && b && a[0] == b[0] && a[1] == b[1];
58405
+ }
58406
+
57959
58407
  cmd.proj = function(dataset, catalog, opts, targetLayers) {
57960
58408
  var srcInfo, destInfo, destStr;
57961
58409
  var implicitlyProjectedNames = getImplicitlyTargetedLayerNames(dataset, targetLayers, layerHasGeometry);
@@ -58123,6 +58571,12 @@ ${svg}
58123
58571
  }
58124
58572
  }
58125
58573
 
58574
+ var frameBounds = dest.__projection_topology &&
58575
+ dest.__projection_topology.frame_bounds;
58576
+ if (clipped && dataset.arcs && frameBounds) {
58577
+ splitPolygonFrameChords(dataset, scaleProjectionFrameBounds(frameBounds, dest));
58578
+ }
58579
+
58126
58580
  if (clipped) {
58127
58581
  // TODO: could more selective in cleaning clipped layers
58128
58582
  // (probably only needed when clipped area crosses the antimeridian or includes a pole)
@@ -58138,6 +58592,18 @@ ${svg}
58138
58592
  dataset.info.crs = dest;
58139
58593
  }
58140
58594
 
58595
+ function scaleProjectionFrameBounds(bounds, crs) {
58596
+ var scale = crs.a * crs.fr_meter;
58597
+ var dx = crs.x0 * crs.fr_meter;
58598
+ var dy = crs.y0 * crs.fr_meter;
58599
+ return [
58600
+ bounds[0] * scale + dx,
58601
+ bounds[1] * scale + dy,
58602
+ bounds[2] * scale + dx,
58603
+ bounds[3] * scale + dy
58604
+ ];
58605
+ }
58606
+
58141
58607
  function projectRasterLayer(lyr, src, dest, opts) {
58142
58608
  var raster = lyr.raster;
58143
58609
  raster.grid = projectRasterGridForward(raster, src, dest, opts || {});
@@ -66237,7 +66703,10 @@ ${svg}
66237
66703
  var src = parseCrsString$1('wgs84');
66238
66704
  var outline = getOutlineDataset(src, dest, {});
66239
66705
  var graticule = importGeoJSON(createGraticule(dest, !!outline, opts));
66240
- projectDataset(graticule, src, dest, {no_clip: false}); // TODO: densify?
66706
+ projectDataset(graticule, src, dest, {
66707
+ no_clip: false,
66708
+ densify: isInterruptedProjection(dest)
66709
+ });
66241
66710
  if (outline) {
66242
66711
  graticule = addOutlineToGraticule(graticule, outline);
66243
66712
  }
@@ -72863,7 +73332,7 @@ ${svg}
72863
73332
  return name == 'rectangle' || name == 'rectangles' || name == 'filter' && opts.cleanup;
72864
73333
  }
72865
73334
 
72866
- var version = "0.7.47";
73335
+ var version = "0.7.48";
72867
73336
 
72868
73337
  // Parse command line args into commands and run them
72869
73338
  // Function takes an optional Node-style callback. A Promise is returned if no callback is given.