mapshaper 0.7.36 → 0.7.37
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 +67 -27
- package/package.json +1 -1
- package/www/mapshaper.js +67 -27
package/mapshaper.js
CHANGED
|
@@ -63744,7 +63744,6 @@ ${svg}
|
|
|
63744
63744
|
var L = t[n - 1];
|
|
63745
63745
|
var m = cyclic ? n - 1 : n;
|
|
63746
63746
|
if (cyclic && m < 3) return [];
|
|
63747
|
-
var segLen = cyclic ? ringSegLengths(t, m) : null;
|
|
63748
63747
|
var W = params.tangentWindow;
|
|
63749
63748
|
var Wi = params.innerWindow;
|
|
63750
63749
|
var turns = new Float64Array(m);
|
|
@@ -63752,8 +63751,8 @@ ${svg}
|
|
|
63752
63751
|
var lo = cyclic ? 0 : 1;
|
|
63753
63752
|
var hi = cyclic ? m : n - 1; // exclusive
|
|
63754
63753
|
for (var i = lo; i < hi; i++) {
|
|
63755
|
-
turns[i] = windowedTurn(t, channels, K, n, L, m,
|
|
63756
|
-
inner[i] = windowedTurn(t, channels, K, n, L, m,
|
|
63754
|
+
turns[i] = windowedTurn(t, channels, K, n, L, m, i, W, cyclic);
|
|
63755
|
+
inner[i] = windowedTurn(t, channels, K, n, L, m, i, Wi, cyclic);
|
|
63757
63756
|
}
|
|
63758
63757
|
// candidates above the angle threshold, that are concentrated (a localized
|
|
63759
63758
|
// turn, not gradual bending -- see isConcentratedTurn), and that are the
|
|
@@ -63876,8 +63875,7 @@ ${svg}
|
|
|
63876
63875
|
var K = channels.length;
|
|
63877
63876
|
var L = t[n - 1];
|
|
63878
63877
|
var m = cyclic ? n - 1 : n;
|
|
63879
|
-
|
|
63880
|
-
return windowedTurn(t, channels, K, n, L, m, segLen, i, params.tangentWindow, cyclic);
|
|
63878
|
+
return windowedTurn(t, channels, K, n, L, m, i, params.tangentWindow, cyclic);
|
|
63881
63879
|
}
|
|
63882
63880
|
|
|
63883
63881
|
// Does the open span [a, b] justify pinning the corner at vertex @corner: is it a
|
|
@@ -63899,18 +63897,12 @@ ${svg}
|
|
|
63899
63897
|
|
|
63900
63898
|
// --- internals ---
|
|
63901
63899
|
|
|
63902
|
-
function ringSegLengths(t, m) {
|
|
63903
|
-
var segLen = new Float64Array(m);
|
|
63904
|
-
for (var i = 0; i < m; i++) segLen[i] = t[i + 1] - t[i];
|
|
63905
|
-
return segLen;
|
|
63906
|
-
}
|
|
63907
|
-
|
|
63908
63900
|
// Turn angle at vertex i between the incoming and outgoing directions, each
|
|
63909
63901
|
// estimated over an arc-length window W (so the measure is scale-aware and not
|
|
63910
63902
|
// dominated by a single short segment).
|
|
63911
|
-
function windowedTurn(t, channels, K, n, L, m,
|
|
63912
|
-
var back = reach(t,
|
|
63913
|
-
var fwd = reach(t,
|
|
63903
|
+
function windowedTurn(t, channels, K, n, L, m, i, W, cyclic) {
|
|
63904
|
+
var back = reach(t, n, m, L, i, -1, W, cyclic);
|
|
63905
|
+
var fwd = reach(t, n, m, L, i, 1, W, cyclic);
|
|
63914
63906
|
var pi = getPt(channels, K, i);
|
|
63915
63907
|
var pb = getPt(channels, K, back);
|
|
63916
63908
|
var pf = getPt(channels, K, fwd);
|
|
@@ -63935,13 +63927,21 @@ ${svg}
|
|
|
63935
63927
|
|
|
63936
63928
|
// Walk from vertex i in direction dir (+1/-1) until accumulated arc length
|
|
63937
63929
|
// reaches W (or a boundary, for open arcs), returning the reached vertex index.
|
|
63938
|
-
|
|
63930
|
+
// Segment lengths are read straight from the cumulative-length array t (t has
|
|
63931
|
+
// n = m+1 entries with t[m] = L, so t[j+1]-t[j] is valid for every ring vertex
|
|
63932
|
+
// j in 0..m-1, including the closing segment); this avoids allocating a per-ring
|
|
63933
|
+
// segment-length array on every call (cornerTurn is hit ~twice per corner).
|
|
63934
|
+
function reach(t, n, m, L, i, dir, W, cyclic) {
|
|
63939
63935
|
var j = i, acc = 0;
|
|
63940
63936
|
while (acc < W) {
|
|
63941
63937
|
if (cyclic) {
|
|
63942
|
-
|
|
63943
|
-
|
|
63944
|
-
|
|
63938
|
+
if (dir > 0) {
|
|
63939
|
+
acc += t[j + 1] - t[j]; // vertex j -> j+1 (t[m] == L handles the seam)
|
|
63940
|
+
j = j + 1 === m ? 0 : j + 1;
|
|
63941
|
+
} else {
|
|
63942
|
+
acc += j > 0 ? t[j] - t[j - 1] : L - t[m - 1]; // vertex j -> j-1
|
|
63943
|
+
j = (j - 1 + m) % m;
|
|
63944
|
+
}
|
|
63945
63945
|
if (j === i) break; // wrapped the whole ring
|
|
63946
63946
|
} else {
|
|
63947
63947
|
var nk = j + dir;
|
|
@@ -63953,14 +63953,39 @@ ${svg}
|
|
|
63953
63953
|
return j;
|
|
63954
63954
|
}
|
|
63955
63955
|
|
|
63956
|
+
// Non-maximum suppression: is vertex j the sharpest turn within an arc-length
|
|
63957
|
+
// window W (ties broken toward the lower index)? Only the vertices within W of j
|
|
63958
|
+
// are examined -- walking outward from j in each direction and stopping once the
|
|
63959
|
+
// arc-length gap reaches W -- rather than scanning the whole arc for every
|
|
63960
|
+
// candidate, which was O(vertices^2) when many vertices are candidates (e.g. a
|
|
63961
|
+
// large ring smoothed below its vertex spacing). Cumulative arc length is
|
|
63962
|
+
// monotone, so the outward gap only grows and the early break is safe; a vertex
|
|
63963
|
+
// within the cyclic window is reached going forward or backward (or both on a
|
|
63964
|
+
// tiny ring, which is harmless for an all-or-nothing test).
|
|
63956
63965
|
function isLocalMaxTurn(t, turns, j, W, L, m, lo, hi, cyclic) {
|
|
63957
|
-
|
|
63958
|
-
|
|
63959
|
-
|
|
63960
|
-
|
|
63961
|
-
|
|
63962
|
-
|
|
63966
|
+
var k, d;
|
|
63967
|
+
if (cyclic) {
|
|
63968
|
+
for (k = (j + 1) % m; k !== j; k = (k + 1) % m) {
|
|
63969
|
+
d = t[k] - t[j];
|
|
63970
|
+
if (d < 0) d += L; // forward arc distance
|
|
63971
|
+
if (d >= W) break;
|
|
63972
|
+
if (turns[k] > turns[j] || (turns[k] === turns[j] && k < j)) return false;
|
|
63973
|
+
}
|
|
63974
|
+
for (k = (j - 1 + m) % m; k !== j; k = (k - 1 + m) % m) {
|
|
63975
|
+
d = t[j] - t[k];
|
|
63976
|
+
if (d < 0) d += L; // backward arc distance
|
|
63977
|
+
if (d >= W) break;
|
|
63978
|
+
if (turns[k] > turns[j] || (turns[k] === turns[j] && k < j)) return false;
|
|
63963
63979
|
}
|
|
63980
|
+
return true;
|
|
63981
|
+
}
|
|
63982
|
+
for (k = j + 1; k < hi; k++) {
|
|
63983
|
+
if (t[k] - t[j] >= W) break;
|
|
63984
|
+
if (turns[k] > turns[j] || (turns[k] === turns[j] && k < j)) return false;
|
|
63985
|
+
}
|
|
63986
|
+
for (k = j - 1; k >= lo; k--) {
|
|
63987
|
+
if (t[j] - t[k] >= W) break;
|
|
63988
|
+
if (turns[k] > turns[j] || (turns[k] === turns[j] && k < j)) return false;
|
|
63964
63989
|
}
|
|
63965
63990
|
return true;
|
|
63966
63991
|
}
|
|
@@ -64311,7 +64336,14 @@ ${svg}
|
|
|
64311
64336
|
if (!leftStruct && !rightStruct) {
|
|
64312
64337
|
bounds.splice(i, 1);
|
|
64313
64338
|
changed = true;
|
|
64314
|
-
|
|
64339
|
+
// Removing bounds[i] only changes the spans of its two neighbours; the
|
|
64340
|
+
// breakpoints before them stay stable, so resume the scan just before the
|
|
64341
|
+
// removal (rechecking the left neighbour) instead of restarting from the
|
|
64342
|
+
// start. Restarting made this O(breaks^2) -- a hang on a large ring where
|
|
64343
|
+
// the smoothing distance is finer than the vertex spacing and nearly
|
|
64344
|
+
// every vertex reads as a breakpoint. The removal sequence is identical to
|
|
64345
|
+
// a from-scratch rescan (the stable prefix is never revisited).
|
|
64346
|
+
i = i < 2 ? 0 : i - 2;
|
|
64315
64347
|
}
|
|
64316
64348
|
}
|
|
64317
64349
|
}
|
|
@@ -64344,7 +64376,15 @@ ${svg}
|
|
|
64344
64376
|
if (!leftStruct && !rightStruct) {
|
|
64345
64377
|
list.splice(i, 1);
|
|
64346
64378
|
changed = true;
|
|
64347
|
-
|
|
64379
|
+
// As in refineBounds, only the removed corner's neighbours change, so
|
|
64380
|
+
// resume just before the removal (i-- via i-2) rather than restarting the
|
|
64381
|
+
// scan -- restarting is what made this O(corners^2) and hung on large
|
|
64382
|
+
// rings smoothed below their vertex spacing (~half the vertices read as
|
|
64383
|
+
// corners, nearly all culled). Cross-seam effects (the wrap between the
|
|
64384
|
+
// last and first corner) are picked up by the outer while(changed) pass.
|
|
64385
|
+
// The stable prefix is never revisited, so the surviving set matches a
|
|
64386
|
+
// from-scratch rescan exactly.
|
|
64387
|
+
i = i < 2 ? -1 : i - 2;
|
|
64348
64388
|
}
|
|
64349
64389
|
}
|
|
64350
64390
|
}
|
|
@@ -66812,7 +66852,7 @@ ${svg}
|
|
|
66812
66852
|
return name == 'rectangle' || name == 'rectangles' || name == 'filter' && opts.cleanup;
|
|
66813
66853
|
}
|
|
66814
66854
|
|
|
66815
|
-
var version = "0.7.
|
|
66855
|
+
var version = "0.7.37";
|
|
66816
66856
|
|
|
66817
66857
|
// Parse command line args into commands and run them
|
|
66818
66858
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|
package/package.json
CHANGED
package/www/mapshaper.js
CHANGED
|
@@ -63744,7 +63744,6 @@ ${svg}
|
|
|
63744
63744
|
var L = t[n - 1];
|
|
63745
63745
|
var m = cyclic ? n - 1 : n;
|
|
63746
63746
|
if (cyclic && m < 3) return [];
|
|
63747
|
-
var segLen = cyclic ? ringSegLengths(t, m) : null;
|
|
63748
63747
|
var W = params.tangentWindow;
|
|
63749
63748
|
var Wi = params.innerWindow;
|
|
63750
63749
|
var turns = new Float64Array(m);
|
|
@@ -63752,8 +63751,8 @@ ${svg}
|
|
|
63752
63751
|
var lo = cyclic ? 0 : 1;
|
|
63753
63752
|
var hi = cyclic ? m : n - 1; // exclusive
|
|
63754
63753
|
for (var i = lo; i < hi; i++) {
|
|
63755
|
-
turns[i] = windowedTurn(t, channels, K, n, L, m,
|
|
63756
|
-
inner[i] = windowedTurn(t, channels, K, n, L, m,
|
|
63754
|
+
turns[i] = windowedTurn(t, channels, K, n, L, m, i, W, cyclic);
|
|
63755
|
+
inner[i] = windowedTurn(t, channels, K, n, L, m, i, Wi, cyclic);
|
|
63757
63756
|
}
|
|
63758
63757
|
// candidates above the angle threshold, that are concentrated (a localized
|
|
63759
63758
|
// turn, not gradual bending -- see isConcentratedTurn), and that are the
|
|
@@ -63876,8 +63875,7 @@ ${svg}
|
|
|
63876
63875
|
var K = channels.length;
|
|
63877
63876
|
var L = t[n - 1];
|
|
63878
63877
|
var m = cyclic ? n - 1 : n;
|
|
63879
|
-
|
|
63880
|
-
return windowedTurn(t, channels, K, n, L, m, segLen, i, params.tangentWindow, cyclic);
|
|
63878
|
+
return windowedTurn(t, channels, K, n, L, m, i, params.tangentWindow, cyclic);
|
|
63881
63879
|
}
|
|
63882
63880
|
|
|
63883
63881
|
// Does the open span [a, b] justify pinning the corner at vertex @corner: is it a
|
|
@@ -63899,18 +63897,12 @@ ${svg}
|
|
|
63899
63897
|
|
|
63900
63898
|
// --- internals ---
|
|
63901
63899
|
|
|
63902
|
-
function ringSegLengths(t, m) {
|
|
63903
|
-
var segLen = new Float64Array(m);
|
|
63904
|
-
for (var i = 0; i < m; i++) segLen[i] = t[i + 1] - t[i];
|
|
63905
|
-
return segLen;
|
|
63906
|
-
}
|
|
63907
|
-
|
|
63908
63900
|
// Turn angle at vertex i between the incoming and outgoing directions, each
|
|
63909
63901
|
// estimated over an arc-length window W (so the measure is scale-aware and not
|
|
63910
63902
|
// dominated by a single short segment).
|
|
63911
|
-
function windowedTurn(t, channels, K, n, L, m,
|
|
63912
|
-
var back = reach(t,
|
|
63913
|
-
var fwd = reach(t,
|
|
63903
|
+
function windowedTurn(t, channels, K, n, L, m, i, W, cyclic) {
|
|
63904
|
+
var back = reach(t, n, m, L, i, -1, W, cyclic);
|
|
63905
|
+
var fwd = reach(t, n, m, L, i, 1, W, cyclic);
|
|
63914
63906
|
var pi = getPt(channels, K, i);
|
|
63915
63907
|
var pb = getPt(channels, K, back);
|
|
63916
63908
|
var pf = getPt(channels, K, fwd);
|
|
@@ -63935,13 +63927,21 @@ ${svg}
|
|
|
63935
63927
|
|
|
63936
63928
|
// Walk from vertex i in direction dir (+1/-1) until accumulated arc length
|
|
63937
63929
|
// reaches W (or a boundary, for open arcs), returning the reached vertex index.
|
|
63938
|
-
|
|
63930
|
+
// Segment lengths are read straight from the cumulative-length array t (t has
|
|
63931
|
+
// n = m+1 entries with t[m] = L, so t[j+1]-t[j] is valid for every ring vertex
|
|
63932
|
+
// j in 0..m-1, including the closing segment); this avoids allocating a per-ring
|
|
63933
|
+
// segment-length array on every call (cornerTurn is hit ~twice per corner).
|
|
63934
|
+
function reach(t, n, m, L, i, dir, W, cyclic) {
|
|
63939
63935
|
var j = i, acc = 0;
|
|
63940
63936
|
while (acc < W) {
|
|
63941
63937
|
if (cyclic) {
|
|
63942
|
-
|
|
63943
|
-
|
|
63944
|
-
|
|
63938
|
+
if (dir > 0) {
|
|
63939
|
+
acc += t[j + 1] - t[j]; // vertex j -> j+1 (t[m] == L handles the seam)
|
|
63940
|
+
j = j + 1 === m ? 0 : j + 1;
|
|
63941
|
+
} else {
|
|
63942
|
+
acc += j > 0 ? t[j] - t[j - 1] : L - t[m - 1]; // vertex j -> j-1
|
|
63943
|
+
j = (j - 1 + m) % m;
|
|
63944
|
+
}
|
|
63945
63945
|
if (j === i) break; // wrapped the whole ring
|
|
63946
63946
|
} else {
|
|
63947
63947
|
var nk = j + dir;
|
|
@@ -63953,14 +63953,39 @@ ${svg}
|
|
|
63953
63953
|
return j;
|
|
63954
63954
|
}
|
|
63955
63955
|
|
|
63956
|
+
// Non-maximum suppression: is vertex j the sharpest turn within an arc-length
|
|
63957
|
+
// window W (ties broken toward the lower index)? Only the vertices within W of j
|
|
63958
|
+
// are examined -- walking outward from j in each direction and stopping once the
|
|
63959
|
+
// arc-length gap reaches W -- rather than scanning the whole arc for every
|
|
63960
|
+
// candidate, which was O(vertices^2) when many vertices are candidates (e.g. a
|
|
63961
|
+
// large ring smoothed below its vertex spacing). Cumulative arc length is
|
|
63962
|
+
// monotone, so the outward gap only grows and the early break is safe; a vertex
|
|
63963
|
+
// within the cyclic window is reached going forward or backward (or both on a
|
|
63964
|
+
// tiny ring, which is harmless for an all-or-nothing test).
|
|
63956
63965
|
function isLocalMaxTurn(t, turns, j, W, L, m, lo, hi, cyclic) {
|
|
63957
|
-
|
|
63958
|
-
|
|
63959
|
-
|
|
63960
|
-
|
|
63961
|
-
|
|
63962
|
-
|
|
63966
|
+
var k, d;
|
|
63967
|
+
if (cyclic) {
|
|
63968
|
+
for (k = (j + 1) % m; k !== j; k = (k + 1) % m) {
|
|
63969
|
+
d = t[k] - t[j];
|
|
63970
|
+
if (d < 0) d += L; // forward arc distance
|
|
63971
|
+
if (d >= W) break;
|
|
63972
|
+
if (turns[k] > turns[j] || (turns[k] === turns[j] && k < j)) return false;
|
|
63973
|
+
}
|
|
63974
|
+
for (k = (j - 1 + m) % m; k !== j; k = (k - 1 + m) % m) {
|
|
63975
|
+
d = t[j] - t[k];
|
|
63976
|
+
if (d < 0) d += L; // backward arc distance
|
|
63977
|
+
if (d >= W) break;
|
|
63978
|
+
if (turns[k] > turns[j] || (turns[k] === turns[j] && k < j)) return false;
|
|
63963
63979
|
}
|
|
63980
|
+
return true;
|
|
63981
|
+
}
|
|
63982
|
+
for (k = j + 1; k < hi; k++) {
|
|
63983
|
+
if (t[k] - t[j] >= W) break;
|
|
63984
|
+
if (turns[k] > turns[j] || (turns[k] === turns[j] && k < j)) return false;
|
|
63985
|
+
}
|
|
63986
|
+
for (k = j - 1; k >= lo; k--) {
|
|
63987
|
+
if (t[j] - t[k] >= W) break;
|
|
63988
|
+
if (turns[k] > turns[j] || (turns[k] === turns[j] && k < j)) return false;
|
|
63964
63989
|
}
|
|
63965
63990
|
return true;
|
|
63966
63991
|
}
|
|
@@ -64311,7 +64336,14 @@ ${svg}
|
|
|
64311
64336
|
if (!leftStruct && !rightStruct) {
|
|
64312
64337
|
bounds.splice(i, 1);
|
|
64313
64338
|
changed = true;
|
|
64314
|
-
|
|
64339
|
+
// Removing bounds[i] only changes the spans of its two neighbours; the
|
|
64340
|
+
// breakpoints before them stay stable, so resume the scan just before the
|
|
64341
|
+
// removal (rechecking the left neighbour) instead of restarting from the
|
|
64342
|
+
// start. Restarting made this O(breaks^2) -- a hang on a large ring where
|
|
64343
|
+
// the smoothing distance is finer than the vertex spacing and nearly
|
|
64344
|
+
// every vertex reads as a breakpoint. The removal sequence is identical to
|
|
64345
|
+
// a from-scratch rescan (the stable prefix is never revisited).
|
|
64346
|
+
i = i < 2 ? 0 : i - 2;
|
|
64315
64347
|
}
|
|
64316
64348
|
}
|
|
64317
64349
|
}
|
|
@@ -64344,7 +64376,15 @@ ${svg}
|
|
|
64344
64376
|
if (!leftStruct && !rightStruct) {
|
|
64345
64377
|
list.splice(i, 1);
|
|
64346
64378
|
changed = true;
|
|
64347
|
-
|
|
64379
|
+
// As in refineBounds, only the removed corner's neighbours change, so
|
|
64380
|
+
// resume just before the removal (i-- via i-2) rather than restarting the
|
|
64381
|
+
// scan -- restarting is what made this O(corners^2) and hung on large
|
|
64382
|
+
// rings smoothed below their vertex spacing (~half the vertices read as
|
|
64383
|
+
// corners, nearly all culled). Cross-seam effects (the wrap between the
|
|
64384
|
+
// last and first corner) are picked up by the outer while(changed) pass.
|
|
64385
|
+
// The stable prefix is never revisited, so the surviving set matches a
|
|
64386
|
+
// from-scratch rescan exactly.
|
|
64387
|
+
i = i < 2 ? -1 : i - 2;
|
|
64348
64388
|
}
|
|
64349
64389
|
}
|
|
64350
64390
|
}
|
|
@@ -66812,7 +66852,7 @@ ${svg}
|
|
|
66812
66852
|
return name == 'rectangle' || name == 'rectangles' || name == 'filter' && opts.cleanup;
|
|
66813
66853
|
}
|
|
66814
66854
|
|
|
66815
|
-
var version = "0.7.
|
|
66855
|
+
var version = "0.7.37";
|
|
66816
66856
|
|
|
66817
66857
|
// Parse command line args into commands and run them
|
|
66818
66858
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|