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.
- package/mapshaper.js +549 -80
- package/package.json +1 -1
- 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$
|
|
81
|
+
function clamp$5(val, min, max) {
|
|
82
82
|
return val < min ? min : (val > max ? max : val);
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -721,7 +721,7 @@
|
|
|
721
721
|
function findValueByRank(arr, rank) {
|
|
722
722
|
if (!arr.length || rank < 1 || rank > arr.length) error$1("[findValueByRank()] invalid input");
|
|
723
723
|
|
|
724
|
-
rank = clamp$
|
|
724
|
+
rank = clamp$5(rank | 0, 1, arr.length);
|
|
725
725
|
var k = rank - 1, // conv. rank to array index
|
|
726
726
|
n = arr.length,
|
|
727
727
|
l = 0,
|
|
@@ -1095,7 +1095,7 @@
|
|
|
1095
1095
|
// self-import and the resulting Rollup circular-dependency warning.
|
|
1096
1096
|
var utils = {
|
|
1097
1097
|
addThousandsSep, addslashes, arrayToIndex,
|
|
1098
|
-
clamp: clamp$
|
|
1098
|
+
clamp: clamp$5, cleanNumericString, contains, copyElements, countValues, createBuffer,
|
|
1099
1099
|
defaults, difference,
|
|
1100
1100
|
endsWith, every, expandoBuffer, extend: extend$1, extendBuffer,
|
|
1101
1101
|
find: find$1, findMedian, findQuantile, findRankByValue, findStringPrefix,
|
|
@@ -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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
8716
|
-
y = clamp$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
8885
|
-
else lonOut = lon0 - Math.acos(clamp$
|
|
8928
|
+
if (Math.sin(lon) > 0) lonOut = lon0 + Math.acos(clamp$3(value, -1, 1));
|
|
8929
|
+
else lonOut = lon0 - Math.acos(clamp$3(value, -1, 1));
|
|
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$
|
|
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$
|
|
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$
|
|
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(
|
|
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
|
-
//
|
|
9105
|
-
//
|
|
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
|
-
|
|
9108
|
-
-
|
|
9109
|
-
|
|
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
|
|
9128
|
-
|
|
9129
|
-
|
|
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
|
-
|
|
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
|
|
9153
|
-
|
|
9154
|
-
regions:
|
|
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:
|
|
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:
|
|
9182
|
-
projectRasterRegion:
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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.
|
|
9257
|
-
|
|
9258
|
-
|
|
9259
|
-
|
|
9260
|
-
|
|
9261
|
-
|
|
9262
|
-
|
|
9263
|
-
|
|
9264
|
-
|
|
9265
|
-
|
|
9266
|
-
|
|
9267
|
-
|
|
9268
|
-
|
|
9269
|
-
|
|
9270
|
-
|
|
9271
|
-
|
|
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$
|
|
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
|
-
|
|
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$
|
|
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, {
|
|
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.
|
|
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.
|