mapshaper 0.7.32 → 0.7.33

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
@@ -32930,10 +32930,6 @@ ${svg}
32930
32930
  .option('method', {
32931
32931
  // hidden option (set by the paek/gaussian flags)
32932
32932
  })
32933
- .option('keep-corners', {
32934
- describe: 'preserve sharp corners where straight-line segments meet',
32935
- type: 'flag'
32936
- })
32937
32933
  .option('gain', {
32938
32934
  describe: 'shrinkage-correction (default 1; 0 = none, >1 exaggerates bends)',
32939
32935
  type: 'number'
@@ -32942,6 +32938,22 @@ ${svg}
32942
32938
  describe: 'max bend between output segments in degrees (default is 8)',
32943
32939
  type: 'number'
32944
32940
  })
32941
+ .option('no-corners', {
32942
+ describe: 'round sharp corners instead of preserving them (on by default)',
32943
+ type: 'flag'
32944
+ })
32945
+ .option('corner-bias', {
32946
+ // undocumented: corner-preservation sensitivity (default 1). Its inverse
32947
+ // scales the min structural-run length, so corner-bias=0.5 doubles it (fewer
32948
+ // corners kept) and corner-bias=2 halves it (more corners kept).
32949
+ // corner-bias=0 turns corner preservation off entirely.
32950
+ type: 'number'
32951
+ })
32952
+ .option('prefilter-gate', {
32953
+ // undocumented: prefilter sinuosity (path/chord) threshold for cutting
32954
+ // intricate detail (default 4; higher removes less)
32955
+ type: 'number'
32956
+ })
32945
32957
  .option('planar', {
32946
32958
  // describe: 'smooth decimal degree coords in 2D space (default is spherical)',
32947
32959
  type: 'flag'
@@ -57268,7 +57280,7 @@ ${svg}
57268
57280
  // Returns {xx: [], yy: []}. Arc endpoints are always preserved, so shared
57269
57281
  // topology nodes stay put and the operation is topology-safe like -simplify.
57270
57282
  var DEFAULT_WEIGHTING = 0.7;
57271
- var DEFAULT_TORTUOSITY = 2;
57283
+ var DEFAULT_TORTUOSITY = 4;
57272
57284
  // How far (in detail-distances of arc length) the survivor-merge pass looks ahead
57273
57285
  // for a chord that closes a convoluted excursion. Bounds the pass to O(n) and
57274
57286
  // caps how long a thin spike it can slice in one merge.
@@ -62345,7 +62357,8 @@ ${svg}
62345
62357
  useSphericalSimplify: useSphericalSimplify
62346
62358
  });
62347
62359
 
62348
- // Structural-corner detection for -smooth's "keep-corners" option.
62360
+ // Structural-corner detection for -smooth's corner preservation (on by default;
62361
+ // disabled with no-corners or corner-bias=0).
62349
62362
  //
62350
62363
  // Many boundaries alternate between natural, freely-curving stretches (coast,
62351
62364
  // river centerline) and artificial straight-line segments (state/county
@@ -62381,14 +62394,18 @@ ${svg}
62381
62394
  var MIN_RUN_LEN_FACTOR = 1.0; // a structural run must be at least tol * this long
62382
62395
  var MIN_RUN_RADIUS_FACTOR = 1.0; // and bend no tighter than radius tol * this
62383
62396
 
62384
- function getCornerParams(tol) {
62397
+ // @cornerBias (optional, default 1) divides the min structural-run length, so a
62398
+ // value < 1 lengthens the run a corner must border to be preserved (fewer, only
62399
+ // well-supported corners), and a value > 1 shortens it (more corners kept).
62400
+ function getCornerParams(tol, cornerBias) {
62401
+ var bias = cornerBias > 0 ? cornerBias : 1;
62385
62402
  return {
62386
62403
  tol: tol,
62387
62404
  cornerAngle: CORNER_ANGLE,
62388
62405
  tangentWindow: TANGENT_WINDOW_FACTOR * tol,
62389
62406
  innerWindow: INNER_WINDOW_FACTOR * TANGENT_WINDOW_FACTOR * tol,
62390
62407
  concentration: CORNER_CONCENTRATION,
62391
- minRunLen: MIN_RUN_LEN_FACTOR * tol,
62408
+ minRunLen: MIN_RUN_LEN_FACTOR * tol / bias,
62392
62409
  maxTurnRate: 1 / (MIN_RUN_RADIUS_FACTOR * tol) // radians of turning per ground unit
62393
62410
  };
62394
62411
  }
@@ -62634,6 +62651,14 @@ ${svg}
62634
62651
  return deg * Math.PI / 180;
62635
62652
  }
62636
62653
 
62654
+ // Resolve the keep-corners run-length bias (default 1). Its inverse scales the
62655
+ // min structural-run length, so a value < 1 protects only longer straight runs
62656
+ // (fewer corners kept) and a value > 1 protects shorter runs (more corners kept).
62657
+ function resolveCornerBias(opts) {
62658
+ var b = opts.cornerBias;
62659
+ return b > 0 ? b : 1;
62660
+ }
62661
+
62637
62662
  function smoothArcCoords(xx, yy, opts) {
62638
62663
  var n = xx.length;
62639
62664
  var origX = toArray(xx);
@@ -62652,6 +62677,7 @@ ${svg}
62652
62677
  method: method,
62653
62678
  spherical: spherical,
62654
62679
  keepCorners: keepCorners,
62680
+ cornerBias: resolveCornerBias(opts),
62655
62681
  gain: resolveGain(opts),
62656
62682
  bendAngle: bendAngle,
62657
62683
  // Refine the dense step for a smaller-than-default bend angle so one dense
@@ -62672,7 +62698,7 @@ ${svg}
62672
62698
 
62673
62699
  if (closed) {
62674
62700
  var corners = keepCorners ?
62675
- findInteriorCorners(t, channels, n, true, getCornerParams(tol)) : [];
62701
+ findInteriorCorners(t, channels, n, true, getCornerParams(tol, ctx.cornerBias)) : [];
62676
62702
  if (corners.length === 0) {
62677
62703
  return smoothClosedCyclic(t, channels, n, ctx);
62678
62704
  }
@@ -62689,7 +62715,7 @@ ${svg}
62689
62715
  }
62690
62716
 
62691
62717
  var openBreaks = keepCorners ?
62692
- findInteriorCorners(t, channels, n, false, getCornerParams(tol)) : [];
62718
+ findInteriorCorners(t, channels, n, false, getCornerParams(tol, ctx.cornerBias)) : [];
62693
62719
  return smoothOpenSpans(origX, origY, t, channels, n, openBreaks, ctx);
62694
62720
  }
62695
62721
 
@@ -62701,9 +62727,9 @@ ${svg}
62701
62727
  var bounds = [0].concat(interiorBreaks);
62702
62728
  bounds.push(n - 1);
62703
62729
  if (ctx.keepCorners && bounds.length > 2) {
62704
- bounds = refineBounds(t, channels, bounds, getCornerParams(ctx.tol));
62730
+ bounds = refineBounds(t, channels, bounds, getCornerParams(ctx.tol, ctx.cornerBias));
62705
62731
  }
62706
- var params = ctx.keepCorners ? getCornerParams(ctx.tol) : null;
62732
+ var params = ctx.keepCorners ? getCornerParams(ctx.tol, ctx.cornerBias) : null;
62707
62733
  var xx = [], yy = [];
62708
62734
  for (var s = 0; s < bounds.length - 1; s++) {
62709
62735
  var lo = bounds[s], hi = bounds[s + 1];
@@ -63209,6 +63235,16 @@ ${svg}
63209
63235
  !(opts.max_bend_angle > 0)) {
63210
63236
  stop$1('Expected max-bend-angle to be a number > 0 (degrees)');
63211
63237
  }
63238
+ if (opts.prefilter_gate !== undefined && opts.prefilter_gate !== null &&
63239
+ !(opts.prefilter_gate > 0)) {
63240
+ stop$1('Expected prefilter-gate to be a number > 0');
63241
+ }
63242
+ if (opts.corner_bias !== undefined && opts.corner_bias !== null &&
63243
+ !(opts.corner_bias >= 0)) {
63244
+ stop$1('Expected corner-bias to be a number >= 0');
63245
+ }
63246
+ // Corner preservation is on by default; no-corners or corner-bias=0 turns it off.
63247
+ var keepCorners = !opts.no_corners && opts.corner_bias !== 0;
63212
63248
  var implicitlySmoothedNames = getImplicitlyTargetedLayerNames(dataset, targetLayers, layerHasPaths);
63213
63249
 
63214
63250
  // Smoothing rewrites coordinates, so lock in any pending (non-destructive)
@@ -63226,6 +63262,7 @@ ${svg}
63226
63262
  var before = arcs.getPointCount();
63227
63263
  filterDetailPaths(arcs, {
63228
63264
  distance: tolerance,
63265
+ tortuosity: opts.prefilter_gate,
63229
63266
  spherical: spherical
63230
63267
  });
63231
63268
  var removed = before - arcs.getPointCount();
@@ -63238,7 +63275,8 @@ ${svg}
63238
63275
  tolerance: tolerance,
63239
63276
  method: method,
63240
63277
  spherical: spherical,
63241
- keepCorners: !!opts.keep_corners,
63278
+ keepCorners: keepCorners,
63279
+ cornerBias: opts.corner_bias,
63242
63280
  gain: opts.gain,
63243
63281
  maxBendAngle: opts.max_bend_angle
63244
63282
  });
@@ -63266,6 +63304,7 @@ ${svg}
63266
63304
  method: opts.method,
63267
63305
  spherical: opts.spherical,
63268
63306
  keepCorners: opts.keepCorners,
63307
+ cornerBias: opts.cornerBias,
63269
63308
  gain: opts.gain,
63270
63309
  maxBendAngle: opts.maxBendAngle,
63271
63310
  closed: arcs.arcIsClosed(arcId)
@@ -65084,7 +65123,7 @@ ${svg}
65084
65123
  return name == 'rectangle' || name == 'rectangles' || name == 'filter' && opts.cleanup;
65085
65124
  }
65086
65125
 
65087
- var version = "0.7.32";
65126
+ var version = "0.7.33";
65088
65127
 
65089
65128
  // Parse command line args into commands and run them
65090
65129
  // 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.32",
3
+ "version": "0.7.33",
4
4
  "description": "A tool for editing geospatial data for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
package/www/mapshaper.js CHANGED
@@ -32930,10 +32930,6 @@ ${svg}
32930
32930
  .option('method', {
32931
32931
  // hidden option (set by the paek/gaussian flags)
32932
32932
  })
32933
- .option('keep-corners', {
32934
- describe: 'preserve sharp corners where straight-line segments meet',
32935
- type: 'flag'
32936
- })
32937
32933
  .option('gain', {
32938
32934
  describe: 'shrinkage-correction (default 1; 0 = none, >1 exaggerates bends)',
32939
32935
  type: 'number'
@@ -32942,6 +32938,22 @@ ${svg}
32942
32938
  describe: 'max bend between output segments in degrees (default is 8)',
32943
32939
  type: 'number'
32944
32940
  })
32941
+ .option('no-corners', {
32942
+ describe: 'round sharp corners instead of preserving them (on by default)',
32943
+ type: 'flag'
32944
+ })
32945
+ .option('corner-bias', {
32946
+ // undocumented: corner-preservation sensitivity (default 1). Its inverse
32947
+ // scales the min structural-run length, so corner-bias=0.5 doubles it (fewer
32948
+ // corners kept) and corner-bias=2 halves it (more corners kept).
32949
+ // corner-bias=0 turns corner preservation off entirely.
32950
+ type: 'number'
32951
+ })
32952
+ .option('prefilter-gate', {
32953
+ // undocumented: prefilter sinuosity (path/chord) threshold for cutting
32954
+ // intricate detail (default 4; higher removes less)
32955
+ type: 'number'
32956
+ })
32945
32957
  .option('planar', {
32946
32958
  // describe: 'smooth decimal degree coords in 2D space (default is spherical)',
32947
32959
  type: 'flag'
@@ -57268,7 +57280,7 @@ ${svg}
57268
57280
  // Returns {xx: [], yy: []}. Arc endpoints are always preserved, so shared
57269
57281
  // topology nodes stay put and the operation is topology-safe like -simplify.
57270
57282
  var DEFAULT_WEIGHTING = 0.7;
57271
- var DEFAULT_TORTUOSITY = 2;
57283
+ var DEFAULT_TORTUOSITY = 4;
57272
57284
  // How far (in detail-distances of arc length) the survivor-merge pass looks ahead
57273
57285
  // for a chord that closes a convoluted excursion. Bounds the pass to O(n) and
57274
57286
  // caps how long a thin spike it can slice in one merge.
@@ -62345,7 +62357,8 @@ ${svg}
62345
62357
  useSphericalSimplify: useSphericalSimplify
62346
62358
  });
62347
62359
 
62348
- // Structural-corner detection for -smooth's "keep-corners" option.
62360
+ // Structural-corner detection for -smooth's corner preservation (on by default;
62361
+ // disabled with no-corners or corner-bias=0).
62349
62362
  //
62350
62363
  // Many boundaries alternate between natural, freely-curving stretches (coast,
62351
62364
  // river centerline) and artificial straight-line segments (state/county
@@ -62381,14 +62394,18 @@ ${svg}
62381
62394
  var MIN_RUN_LEN_FACTOR = 1.0; // a structural run must be at least tol * this long
62382
62395
  var MIN_RUN_RADIUS_FACTOR = 1.0; // and bend no tighter than radius tol * this
62383
62396
 
62384
- function getCornerParams(tol) {
62397
+ // @cornerBias (optional, default 1) divides the min structural-run length, so a
62398
+ // value < 1 lengthens the run a corner must border to be preserved (fewer, only
62399
+ // well-supported corners), and a value > 1 shortens it (more corners kept).
62400
+ function getCornerParams(tol, cornerBias) {
62401
+ var bias = cornerBias > 0 ? cornerBias : 1;
62385
62402
  return {
62386
62403
  tol: tol,
62387
62404
  cornerAngle: CORNER_ANGLE,
62388
62405
  tangentWindow: TANGENT_WINDOW_FACTOR * tol,
62389
62406
  innerWindow: INNER_WINDOW_FACTOR * TANGENT_WINDOW_FACTOR * tol,
62390
62407
  concentration: CORNER_CONCENTRATION,
62391
- minRunLen: MIN_RUN_LEN_FACTOR * tol,
62408
+ minRunLen: MIN_RUN_LEN_FACTOR * tol / bias,
62392
62409
  maxTurnRate: 1 / (MIN_RUN_RADIUS_FACTOR * tol) // radians of turning per ground unit
62393
62410
  };
62394
62411
  }
@@ -62634,6 +62651,14 @@ ${svg}
62634
62651
  return deg * Math.PI / 180;
62635
62652
  }
62636
62653
 
62654
+ // Resolve the keep-corners run-length bias (default 1). Its inverse scales the
62655
+ // min structural-run length, so a value < 1 protects only longer straight runs
62656
+ // (fewer corners kept) and a value > 1 protects shorter runs (more corners kept).
62657
+ function resolveCornerBias(opts) {
62658
+ var b = opts.cornerBias;
62659
+ return b > 0 ? b : 1;
62660
+ }
62661
+
62637
62662
  function smoothArcCoords(xx, yy, opts) {
62638
62663
  var n = xx.length;
62639
62664
  var origX = toArray(xx);
@@ -62652,6 +62677,7 @@ ${svg}
62652
62677
  method: method,
62653
62678
  spherical: spherical,
62654
62679
  keepCorners: keepCorners,
62680
+ cornerBias: resolveCornerBias(opts),
62655
62681
  gain: resolveGain(opts),
62656
62682
  bendAngle: bendAngle,
62657
62683
  // Refine the dense step for a smaller-than-default bend angle so one dense
@@ -62672,7 +62698,7 @@ ${svg}
62672
62698
 
62673
62699
  if (closed) {
62674
62700
  var corners = keepCorners ?
62675
- findInteriorCorners(t, channels, n, true, getCornerParams(tol)) : [];
62701
+ findInteriorCorners(t, channels, n, true, getCornerParams(tol, ctx.cornerBias)) : [];
62676
62702
  if (corners.length === 0) {
62677
62703
  return smoothClosedCyclic(t, channels, n, ctx);
62678
62704
  }
@@ -62689,7 +62715,7 @@ ${svg}
62689
62715
  }
62690
62716
 
62691
62717
  var openBreaks = keepCorners ?
62692
- findInteriorCorners(t, channels, n, false, getCornerParams(tol)) : [];
62718
+ findInteriorCorners(t, channels, n, false, getCornerParams(tol, ctx.cornerBias)) : [];
62693
62719
  return smoothOpenSpans(origX, origY, t, channels, n, openBreaks, ctx);
62694
62720
  }
62695
62721
 
@@ -62701,9 +62727,9 @@ ${svg}
62701
62727
  var bounds = [0].concat(interiorBreaks);
62702
62728
  bounds.push(n - 1);
62703
62729
  if (ctx.keepCorners && bounds.length > 2) {
62704
- bounds = refineBounds(t, channels, bounds, getCornerParams(ctx.tol));
62730
+ bounds = refineBounds(t, channels, bounds, getCornerParams(ctx.tol, ctx.cornerBias));
62705
62731
  }
62706
- var params = ctx.keepCorners ? getCornerParams(ctx.tol) : null;
62732
+ var params = ctx.keepCorners ? getCornerParams(ctx.tol, ctx.cornerBias) : null;
62707
62733
  var xx = [], yy = [];
62708
62734
  for (var s = 0; s < bounds.length - 1; s++) {
62709
62735
  var lo = bounds[s], hi = bounds[s + 1];
@@ -63209,6 +63235,16 @@ ${svg}
63209
63235
  !(opts.max_bend_angle > 0)) {
63210
63236
  stop$1('Expected max-bend-angle to be a number > 0 (degrees)');
63211
63237
  }
63238
+ if (opts.prefilter_gate !== undefined && opts.prefilter_gate !== null &&
63239
+ !(opts.prefilter_gate > 0)) {
63240
+ stop$1('Expected prefilter-gate to be a number > 0');
63241
+ }
63242
+ if (opts.corner_bias !== undefined && opts.corner_bias !== null &&
63243
+ !(opts.corner_bias >= 0)) {
63244
+ stop$1('Expected corner-bias to be a number >= 0');
63245
+ }
63246
+ // Corner preservation is on by default; no-corners or corner-bias=0 turns it off.
63247
+ var keepCorners = !opts.no_corners && opts.corner_bias !== 0;
63212
63248
  var implicitlySmoothedNames = getImplicitlyTargetedLayerNames(dataset, targetLayers, layerHasPaths);
63213
63249
 
63214
63250
  // Smoothing rewrites coordinates, so lock in any pending (non-destructive)
@@ -63226,6 +63262,7 @@ ${svg}
63226
63262
  var before = arcs.getPointCount();
63227
63263
  filterDetailPaths(arcs, {
63228
63264
  distance: tolerance,
63265
+ tortuosity: opts.prefilter_gate,
63229
63266
  spherical: spherical
63230
63267
  });
63231
63268
  var removed = before - arcs.getPointCount();
@@ -63238,7 +63275,8 @@ ${svg}
63238
63275
  tolerance: tolerance,
63239
63276
  method: method,
63240
63277
  spherical: spherical,
63241
- keepCorners: !!opts.keep_corners,
63278
+ keepCorners: keepCorners,
63279
+ cornerBias: opts.corner_bias,
63242
63280
  gain: opts.gain,
63243
63281
  maxBendAngle: opts.max_bend_angle
63244
63282
  });
@@ -63266,6 +63304,7 @@ ${svg}
63266
63304
  method: opts.method,
63267
63305
  spherical: opts.spherical,
63268
63306
  keepCorners: opts.keepCorners,
63307
+ cornerBias: opts.cornerBias,
63269
63308
  gain: opts.gain,
63270
63309
  maxBendAngle: opts.maxBendAngle,
63271
63310
  closed: arcs.arcIsClosed(arcId)
@@ -65084,7 +65123,7 @@ ${svg}
65084
65123
  return name == 'rectangle' || name == 'rectangles' || name == 'filter' && opts.cleanup;
65085
65124
  }
65086
65125
 
65087
- var version = "0.7.32";
65126
+ var version = "0.7.33";
65088
65127
 
65089
65128
  // Parse command line args into commands and run them
65090
65129
  // Function takes an optional Node-style callback. A Promise is returned if no callback is given.