mapshaper 0.7.30 → 0.7.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/mapshaper.js CHANGED
@@ -57238,7 +57238,16 @@ ${svg}
57238
57238
  // distance D) segments the line into runs that each fit within the detail
57239
57239
  // scale and bounds every candidate chord to <= D, so cuts stay local.
57240
57240
  //
57241
- // 2. COMMIT selectively. For each run of removed vertices between two survivors,
57241
+ // 2. MERGE survivors that hide a slicing chord. A spike with long bare flanks
57242
+ // parks its base vertices as survivors (each flank chord alone exceeds D), so
57243
+ // the short chord that closes the excursion sits between non-adjacent
57244
+ // survivors. Where a near-degenerate closing chord (a needle returning close
57245
+ // to its base: chord <= MERGE_CHORD_FRACTION * D, tortuosity >= threshold)
57246
+ // exists within an arc-length window, widen the run so the next phase can
57247
+ // slice it. Restricting to short closing chords keeps the merge from sweeping
57248
+ // a wide excursion across neighbouring geometry and introducing a crossing.
57249
+ //
57250
+ // 3. COMMIT selectively. For each run of removed vertices between two survivors,
57242
57251
  // compare the original sub-path length to the chord across it (tortuosity).
57243
57252
  // Collapse the run to its chord only when it is convoluted (tortuosity >=
57244
57253
  // threshold) -- a jetty, fjord or crinkle. Otherwise restore the run's
@@ -57256,6 +57265,16 @@ ${svg}
57256
57265
  // topology nodes stay put and the operation is topology-safe like -simplify.
57257
57266
  var DEFAULT_WEIGHTING = 0.7;
57258
57267
  var DEFAULT_TORTUOSITY = 2;
57268
+ // How far (in detail-distances of arc length) the survivor-merge pass looks ahead
57269
+ // for a chord that closes a convoluted excursion. Bounds the pass to O(n) and
57270
+ // caps how long a thin spike it can slice in one merge.
57271
+ var MERGE_WINDOW_FACTOR = 12;
57272
+ // The survivor-merge pass only fires when the closing chord is this fraction of D
57273
+ // or shorter: a near-degenerate needle that returns close to its base can be
57274
+ // sliced safely, but collapsing a wider excursion (chord approaching D) sweeps a
57275
+ // long span across neighbouring geometry and can introduce a crossing. cutRun,
57276
+ // which spans only adjacent survivors, is not constrained this way.
57277
+ var MERGE_CHORD_FRACTION = 0.5;
57259
57278
 
57260
57279
  function collapseArcDetail(xx, yy, opts) {
57261
57280
  var n = xx.length;
@@ -57378,6 +57397,47 @@ ${svg}
57378
57397
  }
57379
57398
  }
57380
57399
 
57400
+ // Survivor-merge pass. A thin spike with long bare flanks (e.g. a fjord wall or
57401
+ // a dredged channel) forces its base vertices to be parked as survivors -- each
57402
+ // flank chord on its own exceeds D -- so the short chord that actually closes
57403
+ // the excursion is hidden between *non-adjacent* survivors and the per-run
57404
+ // cutRun above never sees it. Walk the survivor chain and, where a later
57405
+ // survivor closes a convoluted excursion with a short chord (<=
57406
+ // MERGE_CHORD_FRACTION * D, tortuosity >= T) within an arc-length window,
57407
+ // splice out the spanned survivors so the run boundary widens and cutRun slices
57408
+ // the spike off. Restricting to short closing chords keeps the merge from
57409
+ // sweeping a wide excursion across neighbouring geometry. This reuses cumLen and the
57410
+ // peel's linked list; it does not re-run the Visvalingam peel. Only non-adjacent
57411
+ // convoluted survivors are merged, so gentle runs (and all existing behaviour)
57412
+ // are untouched.
57413
+ var window = MERGE_WINDOW_FACTOR * D;
57414
+ var mergeChordSq = Dsq * MERGE_CHORD_FRACTION * MERGE_CHORD_FRACTION;
57415
+ var s = 0;
57416
+ while (s !== n - 1) {
57417
+ var mergeJ = -1;
57418
+ var mergeTort = T;
57419
+ var u = next[s];
57420
+ while (cumLen[u] - cumLen[s] <= window) {
57421
+ if (chordSq(s, u) <= mergeChordSq) {
57422
+ var ud = dist(s, u);
57423
+ var utort = ud > 0 ? (cumLen[u] - cumLen[s]) / ud : Infinity;
57424
+ if (utort > mergeTort) {
57425
+ mergeTort = utort;
57426
+ mergeJ = u;
57427
+ }
57428
+ }
57429
+ if (u === n - 1) break;
57430
+ u = next[u];
57431
+ }
57432
+ if (mergeJ > next[s]) {
57433
+ next[s] = mergeJ;
57434
+ prev[mergeJ] = s;
57435
+ s = mergeJ;
57436
+ } else {
57437
+ s = next[s];
57438
+ }
57439
+ }
57440
+
57381
57441
  outX.push(xx[0]);
57382
57442
  outY.push(yy[0]);
57383
57443
  var a = 0;
@@ -64993,7 +65053,7 @@ ${svg}
64993
65053
  return name == 'rectangle' || name == 'rectangles' || name == 'filter' && opts.cleanup;
64994
65054
  }
64995
65055
 
64996
- var version = "0.7.30";
65056
+ var version = "0.7.31";
64997
65057
 
64998
65058
  // Parse command line args into commands and run them
64999
65059
  // Function takes an optional Node-style callback. A Promise is returned if no callback is given.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mapshaper",
3
- "version": "0.7.30",
3
+ "version": "0.7.31",
4
4
  "description": "A tool for editing geospatial data for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
package/www/mapshaper.js CHANGED
@@ -57238,7 +57238,16 @@ ${svg}
57238
57238
  // distance D) segments the line into runs that each fit within the detail
57239
57239
  // scale and bounds every candidate chord to <= D, so cuts stay local.
57240
57240
  //
57241
- // 2. COMMIT selectively. For each run of removed vertices between two survivors,
57241
+ // 2. MERGE survivors that hide a slicing chord. A spike with long bare flanks
57242
+ // parks its base vertices as survivors (each flank chord alone exceeds D), so
57243
+ // the short chord that closes the excursion sits between non-adjacent
57244
+ // survivors. Where a near-degenerate closing chord (a needle returning close
57245
+ // to its base: chord <= MERGE_CHORD_FRACTION * D, tortuosity >= threshold)
57246
+ // exists within an arc-length window, widen the run so the next phase can
57247
+ // slice it. Restricting to short closing chords keeps the merge from sweeping
57248
+ // a wide excursion across neighbouring geometry and introducing a crossing.
57249
+ //
57250
+ // 3. COMMIT selectively. For each run of removed vertices between two survivors,
57242
57251
  // compare the original sub-path length to the chord across it (tortuosity).
57243
57252
  // Collapse the run to its chord only when it is convoluted (tortuosity >=
57244
57253
  // threshold) -- a jetty, fjord or crinkle. Otherwise restore the run's
@@ -57256,6 +57265,16 @@ ${svg}
57256
57265
  // topology nodes stay put and the operation is topology-safe like -simplify.
57257
57266
  var DEFAULT_WEIGHTING = 0.7;
57258
57267
  var DEFAULT_TORTUOSITY = 2;
57268
+ // How far (in detail-distances of arc length) the survivor-merge pass looks ahead
57269
+ // for a chord that closes a convoluted excursion. Bounds the pass to O(n) and
57270
+ // caps how long a thin spike it can slice in one merge.
57271
+ var MERGE_WINDOW_FACTOR = 12;
57272
+ // The survivor-merge pass only fires when the closing chord is this fraction of D
57273
+ // or shorter: a near-degenerate needle that returns close to its base can be
57274
+ // sliced safely, but collapsing a wider excursion (chord approaching D) sweeps a
57275
+ // long span across neighbouring geometry and can introduce a crossing. cutRun,
57276
+ // which spans only adjacent survivors, is not constrained this way.
57277
+ var MERGE_CHORD_FRACTION = 0.5;
57259
57278
 
57260
57279
  function collapseArcDetail(xx, yy, opts) {
57261
57280
  var n = xx.length;
@@ -57378,6 +57397,47 @@ ${svg}
57378
57397
  }
57379
57398
  }
57380
57399
 
57400
+ // Survivor-merge pass. A thin spike with long bare flanks (e.g. a fjord wall or
57401
+ // a dredged channel) forces its base vertices to be parked as survivors -- each
57402
+ // flank chord on its own exceeds D -- so the short chord that actually closes
57403
+ // the excursion is hidden between *non-adjacent* survivors and the per-run
57404
+ // cutRun above never sees it. Walk the survivor chain and, where a later
57405
+ // survivor closes a convoluted excursion with a short chord (<=
57406
+ // MERGE_CHORD_FRACTION * D, tortuosity >= T) within an arc-length window,
57407
+ // splice out the spanned survivors so the run boundary widens and cutRun slices
57408
+ // the spike off. Restricting to short closing chords keeps the merge from
57409
+ // sweeping a wide excursion across neighbouring geometry. This reuses cumLen and the
57410
+ // peel's linked list; it does not re-run the Visvalingam peel. Only non-adjacent
57411
+ // convoluted survivors are merged, so gentle runs (and all existing behaviour)
57412
+ // are untouched.
57413
+ var window = MERGE_WINDOW_FACTOR * D;
57414
+ var mergeChordSq = Dsq * MERGE_CHORD_FRACTION * MERGE_CHORD_FRACTION;
57415
+ var s = 0;
57416
+ while (s !== n - 1) {
57417
+ var mergeJ = -1;
57418
+ var mergeTort = T;
57419
+ var u = next[s];
57420
+ while (cumLen[u] - cumLen[s] <= window) {
57421
+ if (chordSq(s, u) <= mergeChordSq) {
57422
+ var ud = dist(s, u);
57423
+ var utort = ud > 0 ? (cumLen[u] - cumLen[s]) / ud : Infinity;
57424
+ if (utort > mergeTort) {
57425
+ mergeTort = utort;
57426
+ mergeJ = u;
57427
+ }
57428
+ }
57429
+ if (u === n - 1) break;
57430
+ u = next[u];
57431
+ }
57432
+ if (mergeJ > next[s]) {
57433
+ next[s] = mergeJ;
57434
+ prev[mergeJ] = s;
57435
+ s = mergeJ;
57436
+ } else {
57437
+ s = next[s];
57438
+ }
57439
+ }
57440
+
57381
57441
  outX.push(xx[0]);
57382
57442
  outY.push(yy[0]);
57383
57443
  var a = 0;
@@ -64993,7 +65053,7 @@ ${svg}
64993
65053
  return name == 'rectangle' || name == 'rectangles' || name == 'filter' && opts.cleanup;
64994
65054
  }
64995
65055
 
64996
- var version = "0.7.30";
65056
+ var version = "0.7.31";
64997
65057
 
64998
65058
  // Parse command line args into commands and run them
64999
65059
  // Function takes an optional Node-style callback. A Promise is returned if no callback is given.