mapshaper 0.7.59 → 0.7.61

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
@@ -18168,10 +18168,29 @@
18168
18168
  parseSizeParam: parseSizeParam
18169
18169
  });
18170
18170
 
18171
- // Default gap-width as a fraction of the layer's median polygon-ring segment
18172
- // length. Shared by interior fill and exterior close-outer-gaps.
18171
+ // Conservative width as a fraction of the layer's median polygon-ring segment
18172
+ // length. Used for partition min-width and duplicate-boundary search — not for
18173
+ // the default gap-width=auto fill threshold (see getDefaultGapWidth).
18173
18174
  var GAP_WIDTH_SEGMENT_FRACTION = 0.01;
18174
18175
 
18176
+ // Inject gap_width=auto unless the caller already chose a width or a legacy
18177
+ // area/sliver option. Used by -clean, -filter-slivers, and gap partition.
18178
+ function applyDefaultGapWidthOpts(opts) {
18179
+ opts = Object.assign({}, opts);
18180
+ if (opts.gap_width != null) return opts;
18181
+ // Legacy area/sliver options: keep the historical gap_fill_area=auto default.
18182
+ if (opts.gap_fill_area != null || opts.min_gap_area != null ||
18183
+ opts.min_area != null || opts.sliver_control != null) {
18184
+ if (opts.gap_fill_area == null && opts.min_gap_area == null &&
18185
+ opts.min_area == null) {
18186
+ opts.gap_fill_area = 'auto';
18187
+ }
18188
+ return opts;
18189
+ }
18190
+ opts.gap_width = 'auto';
18191
+ return opts;
18192
+ }
18193
+
18175
18194
  // Used by -clean -dissolve -filter-slivers -filter-islands to generate filters
18176
18195
  // for removing small polygon rings / filling mosaic gaps.
18177
18196
  // Prefers gap_width= (including 'auto'). Legacy gap_fill_area / sliver_control
@@ -18317,9 +18336,10 @@
18317
18336
  };
18318
18337
  }
18319
18338
 
18320
- // Median polygon-ring segment length * GAP_WIDTH_SEGMENT_FRACTION.
18339
+ // Width equivalent of the legacy gap-fill-area=auto + sliver-control=1 test:
18340
+ // W = sqrt(A0 / π). The two filters accept the same rings (see getGapWidthTest).
18321
18341
  function getDefaultGapWidth(lyr, arcs) {
18322
- return getMedianPolygonSegmentLength(lyr, arcs) * GAP_WIDTH_SEGMENT_FRACTION;
18342
+ return Math.sqrt(getDefaultSliverThreshold(lyr, arcs) / Math.PI);
18323
18343
  }
18324
18344
 
18325
18345
  function getMedianPolygonSegmentLength(lyr, arcs) {
@@ -18400,6 +18420,7 @@
18400
18420
  var Slivers = /*#__PURE__*/Object.freeze({
18401
18421
  __proto__: null,
18402
18422
  GAP_WIDTH_SEGMENT_FRACTION: GAP_WIDTH_SEGMENT_FRACTION,
18423
+ applyDefaultGapWidthOpts: applyDefaultGapWidthOpts,
18403
18424
  calcMaxSliverArea: calcMaxSliverArea,
18404
18425
  getDefaultGapWidth: getDefaultGapWidth,
18405
18426
  getDefaultSliverThreshold: getDefaultSliverThreshold,
@@ -23467,8 +23488,7 @@
23467
23488
  var spherical = isLatLngCRS(crs);
23468
23489
  var medianSeg = measureMedianSegment(lyr, arcs);
23469
23490
  // Same width as interior gap filling, from the same automatic default.
23470
- var distance = resolveCloseDistance(opts, crs,
23471
- medianSeg * GAP_WIDTH_SEGMENT_FRACTION);
23491
+ var distance = resolveCloseDistance(opts, crs, getDefaultGapWidth(lyr, arcs));
23472
23492
  if (!(distance > 0)) return 0;
23473
23493
 
23474
23494
  profileStart('cg.outsideFacingArcs');
@@ -23518,7 +23538,7 @@
23518
23538
  return {seams: seams, seeds: seeds, arcsById: arcsById, footpoints: footpoints};
23519
23539
  }
23520
23540
 
23521
- // Same segment median as interior gap-width=auto (all polygon-ring segments).
23541
+ // Median of every polygon-ring segment; used for min-seam length.
23522
23542
  function measureMedianSegment(lyr, arcs) {
23523
23543
  return profileWrap('cg.medianSegment', function() {
23524
23544
  return getMedianPolygonSegmentLength(lyr, arcs);
@@ -24154,18 +24174,7 @@
24154
24174
  function partitionPolygonMosaicGaps(lyr, dataset, nodes, opts) {
24155
24175
  if (!lyr.shapes || lyr.shapes.length < MIN_GAP_OWNERS) return false;
24156
24176
  var mosaicIndex = new MosaicIndex(lyr, nodes, {flat: true});
24157
- var sliverOpts = utils.extend({}, opts);
24158
- if (sliverOpts.gap_width == null) {
24159
- if (sliverOpts.gap_fill_area != null || sliverOpts.min_gap_area != null ||
24160
- sliverOpts.min_area != null || sliverOpts.sliver_control != null) {
24161
- if (sliverOpts.gap_fill_area == null && sliverOpts.min_gap_area == null &&
24162
- sliverOpts.min_area == null) {
24163
- sliverOpts.gap_fill_area = 'auto';
24164
- }
24165
- } else {
24166
- sliverOpts.gap_width = 'auto';
24167
- }
24168
- }
24177
+ var sliverOpts = applyDefaultGapWidthOpts(opts);
24169
24178
  var filter = getSliverFilter(lyr, dataset, sliverOpts).filter;
24170
24179
  var gaps = mosaicIndex.getUnusedTileData(filter).filter(function(gap) {
24171
24180
  return countOwners(gap.boundary) >= MIN_GAP_OWNERS;
@@ -24601,10 +24610,11 @@
24601
24610
  // several features with hairline slivers, which is worse for having more of them.
24602
24611
  //
24603
24612
  // A layer's median segment length is the scale at which its boundaries were
24604
- // drawn, so the same fraction of it that serves as the default gap-width -- what
24605
- // mapshaper already treats as too narrow to be intended -- marks where dividing
24606
- // stops being worth it. This is deliberately independent of the gap-width in
24607
- // effect: raising that to fill wider gaps should not coarsen the data's own scale.
24613
+ // drawn. A small fraction of that scale marks where dividing a gap stops being
24614
+ // worth it: the displacement would be smaller than the data's own detail, and
24615
+ // the pieces would be hairline slivers. This is deliberately independent of
24616
+ // the gap-width in effect: raising that to fill wider gaps should not coarsen
24617
+ // the data's own scale.
24608
24618
  function getMinDivisibleGapWidth(lyr, arcs) {
24609
24619
  var width = getMedianPolygonSegmentLength(lyr, arcs) *
24610
24620
  GAP_WIDTH_SEGMENT_FRACTION;
@@ -24741,7 +24751,7 @@
24741
24751
 
24742
24752
  function cleanPolygonLayerGeometry(lyr, dataset, opts) {
24743
24753
  // clean polygons by apply the 'dissolve2' function to each feature
24744
- opts = withDefaultGapWidth(opts);
24754
+ opts = applyDefaultGapWidthOpts(opts);
24745
24755
  var groups = lyr.shapes.map(function(shp, i) {
24746
24756
  return [i];
24747
24757
  });
@@ -24750,22 +24760,6 @@
24750
24760
  markLayerChanged(lyr, {operation: 'cleanPolygonLayerGeometry', unit: 'shapes'});
24751
24761
  }
24752
24762
 
24753
- function withDefaultGapWidth(opts) {
24754
- opts = Object.assign({}, opts);
24755
- if (opts.gap_width != null) return opts;
24756
- // Legacy area/sliver options: keep the historical gap_fill_area=auto default.
24757
- if (opts.gap_fill_area != null || opts.min_gap_area != null ||
24758
- opts.min_area != null || opts.sliver_control != null) {
24759
- if (opts.gap_fill_area == null && opts.min_gap_area == null &&
24760
- opts.min_area == null) {
24761
- opts.gap_fill_area = 'auto';
24762
- }
24763
- return opts;
24764
- }
24765
- opts.gap_width = 'auto';
24766
- return opts;
24767
- }
24768
-
24769
24763
  function collectArcIds(shapes) {
24770
24764
  var ids = {};
24771
24765
  traversePaths(shapes, function(o) {
@@ -40329,12 +40323,13 @@ ${svg}
40329
40323
 
40330
40324
  parser.command('filter-slivers')
40331
40325
  .describe('remove small polygon rings')
40326
+ .option('gap-width', gapWidthOpt)
40332
40327
  .option('min-area', {
40333
40328
  type: 'area',
40334
- describe: 'area threshold (e.g. 2sqkm)'
40329
+ describe: '(deprecated) use gap-width= instead'
40335
40330
  })
40336
40331
  .option('sliver-control', {
40337
- describe: 'boost area threshold of slivers (0-1, default is 1)',
40332
+ describe: '(deprecated) use gap-width= instead',
40338
40333
  type: 'number'
40339
40334
  })
40340
40335
  .option('weighted', {
@@ -56573,7 +56568,13 @@ ${svg}
56573
56568
  };
56574
56569
 
56575
56570
  function filterSlivers(lyr, dataset, optsArg) {
56576
- var opts = utils.extend({sliver_control: 1}, optsArg);
56571
+ var opts = applyDefaultGapWidthOpts(optsArg);
56572
+ // Legacy area path only: keep the historical sliver-control=1 default.
56573
+ // Do not inject it before applyDefaultGapWidthOpts, or the implicit default
56574
+ // would lock the command onto the area path.
56575
+ if (opts.gap_width == null && opts.sliver_control == null) {
56576
+ opts.sliver_control = 1;
56577
+ }
56577
56578
  var filterData = getSliverFilter(lyr, dataset, opts);
56578
56579
  var ringTest = filterData.filter;
56579
56580
  var removed = 0;
@@ -80210,7 +80211,7 @@ ${svg}
80210
80211
  return name == 'rectangle' || name == 'rectangles' || name == 'filter' && opts.cleanup;
80211
80212
  }
80212
80213
 
80213
- var version = "0.7.59";
80214
+ var version = "0.7.61";
80214
80215
 
80215
80216
  // Parse command line args into commands and run them
80216
80217
  // 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.59",
3
+ "version": "0.7.61",
4
4
  "description": "A tool for editing geospatial data for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
package/www/basemap.js CHANGED
@@ -3,7 +3,7 @@ window.mapboxParams = {
3
3
  // css: 'https://api.mapbox.com/mapbox-gl-js/v2.11.1/mapbox-gl.css',
4
4
  js: 'https://api.mapbox.com/mapbox-gl-js/v3.15.0/mapbox-gl.js',
5
5
  css: 'https://api.mapbox.com/mapbox-gl-js/v3.15.0/mapbox-gl.css',
6
- production_key: 'pk.eyJ1IjoiZ3JhbW1hdGEiLCJhIjoiY21jZ2RlbGk1MGhvNzJrcHV2dTYzZWE2byJ9.btkRnRrPW75c0AlQ5lH2cg',
6
+ production_key: 'pk.eyJ1IjoiZ3JhbW1hdGEiLCJhIjoiY210cjg2NTk5MDBiMTJ4b3dvbDNwMjdudSJ9.EohCQlad59ntK8CqWlopKw',
7
7
  localhost_key: 'pk.eyJ1IjoiZ3JhbW1hdGEiLCJhIjoiY21jZ2Rna2hrMGo2ZjJqcHFxMHAycDlyMSJ9.q8FchhB-NAN_FGBHN0AJeg',
8
8
  styles: [{
9
9
  name: 'Reference map',
package/www/mapshaper.js CHANGED
@@ -18168,10 +18168,29 @@
18168
18168
  parseSizeParam: parseSizeParam
18169
18169
  });
18170
18170
 
18171
- // Default gap-width as a fraction of the layer's median polygon-ring segment
18172
- // length. Shared by interior fill and exterior close-outer-gaps.
18171
+ // Conservative width as a fraction of the layer's median polygon-ring segment
18172
+ // length. Used for partition min-width and duplicate-boundary search — not for
18173
+ // the default gap-width=auto fill threshold (see getDefaultGapWidth).
18173
18174
  var GAP_WIDTH_SEGMENT_FRACTION = 0.01;
18174
18175
 
18176
+ // Inject gap_width=auto unless the caller already chose a width or a legacy
18177
+ // area/sliver option. Used by -clean, -filter-slivers, and gap partition.
18178
+ function applyDefaultGapWidthOpts(opts) {
18179
+ opts = Object.assign({}, opts);
18180
+ if (opts.gap_width != null) return opts;
18181
+ // Legacy area/sliver options: keep the historical gap_fill_area=auto default.
18182
+ if (opts.gap_fill_area != null || opts.min_gap_area != null ||
18183
+ opts.min_area != null || opts.sliver_control != null) {
18184
+ if (opts.gap_fill_area == null && opts.min_gap_area == null &&
18185
+ opts.min_area == null) {
18186
+ opts.gap_fill_area = 'auto';
18187
+ }
18188
+ return opts;
18189
+ }
18190
+ opts.gap_width = 'auto';
18191
+ return opts;
18192
+ }
18193
+
18175
18194
  // Used by -clean -dissolve -filter-slivers -filter-islands to generate filters
18176
18195
  // for removing small polygon rings / filling mosaic gaps.
18177
18196
  // Prefers gap_width= (including 'auto'). Legacy gap_fill_area / sliver_control
@@ -18317,9 +18336,10 @@
18317
18336
  };
18318
18337
  }
18319
18338
 
18320
- // Median polygon-ring segment length * GAP_WIDTH_SEGMENT_FRACTION.
18339
+ // Width equivalent of the legacy gap-fill-area=auto + sliver-control=1 test:
18340
+ // W = sqrt(A0 / π). The two filters accept the same rings (see getGapWidthTest).
18321
18341
  function getDefaultGapWidth(lyr, arcs) {
18322
- return getMedianPolygonSegmentLength(lyr, arcs) * GAP_WIDTH_SEGMENT_FRACTION;
18342
+ return Math.sqrt(getDefaultSliverThreshold(lyr, arcs) / Math.PI);
18323
18343
  }
18324
18344
 
18325
18345
  function getMedianPolygonSegmentLength(lyr, arcs) {
@@ -18400,6 +18420,7 @@
18400
18420
  var Slivers = /*#__PURE__*/Object.freeze({
18401
18421
  __proto__: null,
18402
18422
  GAP_WIDTH_SEGMENT_FRACTION: GAP_WIDTH_SEGMENT_FRACTION,
18423
+ applyDefaultGapWidthOpts: applyDefaultGapWidthOpts,
18403
18424
  calcMaxSliverArea: calcMaxSliverArea,
18404
18425
  getDefaultGapWidth: getDefaultGapWidth,
18405
18426
  getDefaultSliverThreshold: getDefaultSliverThreshold,
@@ -23467,8 +23488,7 @@
23467
23488
  var spherical = isLatLngCRS(crs);
23468
23489
  var medianSeg = measureMedianSegment(lyr, arcs);
23469
23490
  // Same width as interior gap filling, from the same automatic default.
23470
- var distance = resolveCloseDistance(opts, crs,
23471
- medianSeg * GAP_WIDTH_SEGMENT_FRACTION);
23491
+ var distance = resolveCloseDistance(opts, crs, getDefaultGapWidth(lyr, arcs));
23472
23492
  if (!(distance > 0)) return 0;
23473
23493
 
23474
23494
  profileStart('cg.outsideFacingArcs');
@@ -23518,7 +23538,7 @@
23518
23538
  return {seams: seams, seeds: seeds, arcsById: arcsById, footpoints: footpoints};
23519
23539
  }
23520
23540
 
23521
- // Same segment median as interior gap-width=auto (all polygon-ring segments).
23541
+ // Median of every polygon-ring segment; used for min-seam length.
23522
23542
  function measureMedianSegment(lyr, arcs) {
23523
23543
  return profileWrap('cg.medianSegment', function() {
23524
23544
  return getMedianPolygonSegmentLength(lyr, arcs);
@@ -24154,18 +24174,7 @@
24154
24174
  function partitionPolygonMosaicGaps(lyr, dataset, nodes, opts) {
24155
24175
  if (!lyr.shapes || lyr.shapes.length < MIN_GAP_OWNERS) return false;
24156
24176
  var mosaicIndex = new MosaicIndex(lyr, nodes, {flat: true});
24157
- var sliverOpts = utils.extend({}, opts);
24158
- if (sliverOpts.gap_width == null) {
24159
- if (sliverOpts.gap_fill_area != null || sliverOpts.min_gap_area != null ||
24160
- sliverOpts.min_area != null || sliverOpts.sliver_control != null) {
24161
- if (sliverOpts.gap_fill_area == null && sliverOpts.min_gap_area == null &&
24162
- sliverOpts.min_area == null) {
24163
- sliverOpts.gap_fill_area = 'auto';
24164
- }
24165
- } else {
24166
- sliverOpts.gap_width = 'auto';
24167
- }
24168
- }
24177
+ var sliverOpts = applyDefaultGapWidthOpts(opts);
24169
24178
  var filter = getSliverFilter(lyr, dataset, sliverOpts).filter;
24170
24179
  var gaps = mosaicIndex.getUnusedTileData(filter).filter(function(gap) {
24171
24180
  return countOwners(gap.boundary) >= MIN_GAP_OWNERS;
@@ -24601,10 +24610,11 @@
24601
24610
  // several features with hairline slivers, which is worse for having more of them.
24602
24611
  //
24603
24612
  // A layer's median segment length is the scale at which its boundaries were
24604
- // drawn, so the same fraction of it that serves as the default gap-width -- what
24605
- // mapshaper already treats as too narrow to be intended -- marks where dividing
24606
- // stops being worth it. This is deliberately independent of the gap-width in
24607
- // effect: raising that to fill wider gaps should not coarsen the data's own scale.
24613
+ // drawn. A small fraction of that scale marks where dividing a gap stops being
24614
+ // worth it: the displacement would be smaller than the data's own detail, and
24615
+ // the pieces would be hairline slivers. This is deliberately independent of
24616
+ // the gap-width in effect: raising that to fill wider gaps should not coarsen
24617
+ // the data's own scale.
24608
24618
  function getMinDivisibleGapWidth(lyr, arcs) {
24609
24619
  var width = getMedianPolygonSegmentLength(lyr, arcs) *
24610
24620
  GAP_WIDTH_SEGMENT_FRACTION;
@@ -24741,7 +24751,7 @@
24741
24751
 
24742
24752
  function cleanPolygonLayerGeometry(lyr, dataset, opts) {
24743
24753
  // clean polygons by apply the 'dissolve2' function to each feature
24744
- opts = withDefaultGapWidth(opts);
24754
+ opts = applyDefaultGapWidthOpts(opts);
24745
24755
  var groups = lyr.shapes.map(function(shp, i) {
24746
24756
  return [i];
24747
24757
  });
@@ -24750,22 +24760,6 @@
24750
24760
  markLayerChanged(lyr, {operation: 'cleanPolygonLayerGeometry', unit: 'shapes'});
24751
24761
  }
24752
24762
 
24753
- function withDefaultGapWidth(opts) {
24754
- opts = Object.assign({}, opts);
24755
- if (opts.gap_width != null) return opts;
24756
- // Legacy area/sliver options: keep the historical gap_fill_area=auto default.
24757
- if (opts.gap_fill_area != null || opts.min_gap_area != null ||
24758
- opts.min_area != null || opts.sliver_control != null) {
24759
- if (opts.gap_fill_area == null && opts.min_gap_area == null &&
24760
- opts.min_area == null) {
24761
- opts.gap_fill_area = 'auto';
24762
- }
24763
- return opts;
24764
- }
24765
- opts.gap_width = 'auto';
24766
- return opts;
24767
- }
24768
-
24769
24763
  function collectArcIds(shapes) {
24770
24764
  var ids = {};
24771
24765
  traversePaths(shapes, function(o) {
@@ -40329,12 +40323,13 @@ ${svg}
40329
40323
 
40330
40324
  parser.command('filter-slivers')
40331
40325
  .describe('remove small polygon rings')
40326
+ .option('gap-width', gapWidthOpt)
40332
40327
  .option('min-area', {
40333
40328
  type: 'area',
40334
- describe: 'area threshold (e.g. 2sqkm)'
40329
+ describe: '(deprecated) use gap-width= instead'
40335
40330
  })
40336
40331
  .option('sliver-control', {
40337
- describe: 'boost area threshold of slivers (0-1, default is 1)',
40332
+ describe: '(deprecated) use gap-width= instead',
40338
40333
  type: 'number'
40339
40334
  })
40340
40335
  .option('weighted', {
@@ -56573,7 +56568,13 @@ ${svg}
56573
56568
  };
56574
56569
 
56575
56570
  function filterSlivers(lyr, dataset, optsArg) {
56576
- var opts = utils.extend({sliver_control: 1}, optsArg);
56571
+ var opts = applyDefaultGapWidthOpts(optsArg);
56572
+ // Legacy area path only: keep the historical sliver-control=1 default.
56573
+ // Do not inject it before applyDefaultGapWidthOpts, or the implicit default
56574
+ // would lock the command onto the area path.
56575
+ if (opts.gap_width == null && opts.sliver_control == null) {
56576
+ opts.sliver_control = 1;
56577
+ }
56577
56578
  var filterData = getSliverFilter(lyr, dataset, opts);
56578
56579
  var ringTest = filterData.filter;
56579
56580
  var removed = 0;
@@ -80210,7 +80211,7 @@ ${svg}
80210
80211
  return name == 'rectangle' || name == 'rectangles' || name == 'filter' && opts.cleanup;
80211
80212
  }
80212
80213
 
80213
- var version = "0.7.59";
80214
+ var version = "0.7.61";
80214
80215
 
80215
80216
  // Parse command line args into commands and run them
80216
80217
  // Function takes an optional Node-style callback. A Promise is returned if no callback is given.