mapshaper 0.7.31 → 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 +97 -27
- package/package.json +1 -1
- package/www/mapshaper.js +97 -27
package/mapshaper.js
CHANGED
|
@@ -32930,14 +32930,30 @@ ${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'
|
|
32940
32936
|
})
|
|
32937
|
+
.option('max-bend-angle', {
|
|
32938
|
+
describe: 'max bend between output segments in degrees (default is 8)',
|
|
32939
|
+
type: 'number'
|
|
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
|
+
})
|
|
32941
32957
|
.option('planar', {
|
|
32942
32958
|
// describe: 'smooth decimal degree coords in 2D space (default is spherical)',
|
|
32943
32959
|
type: 'flag'
|
|
@@ -57264,7 +57280,7 @@ ${svg}
|
|
|
57264
57280
|
// Returns {xx: [], yy: []}. Arc endpoints are always preserved, so shared
|
|
57265
57281
|
// topology nodes stay put and the operation is topology-safe like -simplify.
|
|
57266
57282
|
var DEFAULT_WEIGHTING = 0.7;
|
|
57267
|
-
var DEFAULT_TORTUOSITY =
|
|
57283
|
+
var DEFAULT_TORTUOSITY = 4;
|
|
57268
57284
|
// How far (in detail-distances of arc length) the survivor-merge pass looks ahead
|
|
57269
57285
|
// for a chord that closes a convoluted excursion. Bounds the pass to O(n) and
|
|
57270
57286
|
// caps how long a thin spike it can slice in one merge.
|
|
@@ -62341,7 +62357,8 @@ ${svg}
|
|
|
62341
62357
|
useSphericalSimplify: useSphericalSimplify
|
|
62342
62358
|
});
|
|
62343
62359
|
|
|
62344
|
-
// Structural-corner detection for -smooth's
|
|
62360
|
+
// Structural-corner detection for -smooth's corner preservation (on by default;
|
|
62361
|
+
// disabled with no-corners or corner-bias=0).
|
|
62345
62362
|
//
|
|
62346
62363
|
// Many boundaries alternate between natural, freely-curving stretches (coast,
|
|
62347
62364
|
// river centerline) and artificial straight-line segments (state/county
|
|
@@ -62377,14 +62394,18 @@ ${svg}
|
|
|
62377
62394
|
var MIN_RUN_LEN_FACTOR = 1.0; // a structural run must be at least tol * this long
|
|
62378
62395
|
var MIN_RUN_RADIUS_FACTOR = 1.0; // and bend no tighter than radius tol * this
|
|
62379
62396
|
|
|
62380
|
-
|
|
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;
|
|
62381
62402
|
return {
|
|
62382
62403
|
tol: tol,
|
|
62383
62404
|
cornerAngle: CORNER_ANGLE,
|
|
62384
62405
|
tangentWindow: TANGENT_WINDOW_FACTOR * tol,
|
|
62385
62406
|
innerWindow: INNER_WINDOW_FACTOR * TANGENT_WINDOW_FACTOR * tol,
|
|
62386
62407
|
concentration: CORNER_CONCENTRATION,
|
|
62387
|
-
minRunLen: MIN_RUN_LEN_FACTOR * tol,
|
|
62408
|
+
minRunLen: MIN_RUN_LEN_FACTOR * tol / bias,
|
|
62388
62409
|
maxTurnRate: 1 / (MIN_RUN_RADIUS_FACTOR * tol) // radians of turning per ground unit
|
|
62389
62410
|
};
|
|
62390
62411
|
}
|
|
@@ -62587,20 +62608,25 @@ ${svg}
|
|
|
62587
62608
|
// chord * accumulatedTurn / 8 estimates the bow of a circular arc, and we also
|
|
62588
62609
|
// cut when it exceeds a fraction of the tolerance. Both tests are O(1) per dense
|
|
62589
62610
|
// vertex, so the pass stays O(n).
|
|
62590
|
-
var DENSE_STEP_FACTOR = 0.033; // dense sampling step = tolerance * this
|
|
62591
|
-
// resolve the sharpest
|
|
62592
|
-
// ~ the kernel scale)
|
|
62593
|
-
// angle filter can reach
|
|
62594
|
-
//
|
|
62595
|
-
// kept well under
|
|
62596
|
-
//
|
|
62597
|
-
|
|
62611
|
+
var DENSE_STEP_FACTOR = 0.033; // dense sampling step = tolerance * this at the
|
|
62612
|
+
// default bend angle. Must resolve the sharpest
|
|
62613
|
+
// smoothed feature (radius ~ the kernel scale)
|
|
62614
|
+
// finely enough that the angle filter can reach
|
|
62615
|
+
// the bend-angle joins: one dense segment turns
|
|
62616
|
+
// ~ this/0.4 radians there, kept well under the
|
|
62617
|
+
// bend angle so the discrete accumulation barely
|
|
62618
|
+
// overshoots the threshold. For a smaller-than-
|
|
62619
|
+
// default bend angle the step is refined in
|
|
62620
|
+
// proportion so the threshold stays reachable.
|
|
62621
|
+
var DEFAULT_BEND_ANGLE = 8 * Math.PI / 180; // keep a vertex after this much accumulated
|
|
62622
|
+
// turn (max turn between consecutive output
|
|
62623
|
+
// segments); user-overridable via max-bend-angle
|
|
62598
62624
|
var DEVIATION_FACTOR = 0.1; // sagitta guard: also cut a gentle bend that bows
|
|
62599
62625
|
// more than tolerance * this from its chord
|
|
62600
62626
|
|
|
62601
62627
|
// Smooth a single arc's coordinates.
|
|
62602
62628
|
// @xx, @yy: coordinate arrays (may be typed-array subarrays) for one arc.
|
|
62603
|
-
// @opts: {tolerance, method, spherical, closed, keepCorners}
|
|
62629
|
+
// @opts: {tolerance, method, spherical, closed, keepCorners, gain, maxBendAngle}
|
|
62604
62630
|
// Returns {xx: [], yy: []} with the smoothed coordinates. Endpoints of open
|
|
62605
62631
|
// arcs are preserved exactly (so shared topology nodes stay put); closed arcs
|
|
62606
62632
|
// are smoothed cyclically and returned closed (first point repeated at the end).
|
|
@@ -62615,6 +62641,24 @@ ${svg}
|
|
|
62615
62641
|
return g >= 0 ? g : 0;
|
|
62616
62642
|
}
|
|
62617
62643
|
|
|
62644
|
+
// Resolve the output bend-angle threshold from the user option (in degrees) to
|
|
62645
|
+
// radians. It caps the turn between consecutive output segments: a larger angle
|
|
62646
|
+
// keeps fewer vertices (coarser joins), a smaller one keeps more (smoother joins).
|
|
62647
|
+
// Non-positive or missing values fall back to the default.
|
|
62648
|
+
function resolveBendAngle(opts) {
|
|
62649
|
+
var deg = opts.maxBendAngle;
|
|
62650
|
+
if (deg === undefined || deg === null || !(deg > 0)) return DEFAULT_BEND_ANGLE;
|
|
62651
|
+
return deg * Math.PI / 180;
|
|
62652
|
+
}
|
|
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
|
+
|
|
62618
62662
|
function smoothArcCoords(xx, yy, opts) {
|
|
62619
62663
|
var n = xx.length;
|
|
62620
62664
|
var origX = toArray(xx);
|
|
@@ -62627,12 +62671,19 @@ ${svg}
|
|
|
62627
62671
|
var closed = !!opts.closed;
|
|
62628
62672
|
var spherical = !!opts.spherical;
|
|
62629
62673
|
var keepCorners = !!opts.keepCorners;
|
|
62674
|
+
var bendAngle = resolveBendAngle(opts);
|
|
62630
62675
|
var ctx = {
|
|
62631
62676
|
tol: tol,
|
|
62632
62677
|
method: method,
|
|
62633
62678
|
spherical: spherical,
|
|
62634
62679
|
keepCorners: keepCorners,
|
|
62680
|
+
cornerBias: resolveCornerBias(opts),
|
|
62635
62681
|
gain: resolveGain(opts),
|
|
62682
|
+
bendAngle: bendAngle,
|
|
62683
|
+
// Refine the dense step for a smaller-than-default bend angle so one dense
|
|
62684
|
+
// segment still turns well under the threshold; never coarsen it beyond the
|
|
62685
|
+
// default (the angle filter alone thins the output for larger angles).
|
|
62686
|
+
denseStep: tol * DENSE_STEP_FACTOR * Math.min(1, bendAngle / DEFAULT_BEND_ANGLE),
|
|
62636
62687
|
radius: tol * WINDOW_RADIUS_FACTOR,
|
|
62637
62688
|
scale: (method == 'gaussian' ? GAUSSIAN_SIGMA_FACTOR : PAEK_SCALE_FACTOR) * tol
|
|
62638
62689
|
};
|
|
@@ -62647,7 +62698,7 @@ ${svg}
|
|
|
62647
62698
|
|
|
62648
62699
|
if (closed) {
|
|
62649
62700
|
var corners = keepCorners ?
|
|
62650
|
-
findInteriorCorners(t, channels, n, true, getCornerParams(tol)) : [];
|
|
62701
|
+
findInteriorCorners(t, channels, n, true, getCornerParams(tol, ctx.cornerBias)) : [];
|
|
62651
62702
|
if (corners.length === 0) {
|
|
62652
62703
|
return smoothClosedCyclic(t, channels, n, ctx);
|
|
62653
62704
|
}
|
|
@@ -62664,7 +62715,7 @@ ${svg}
|
|
|
62664
62715
|
}
|
|
62665
62716
|
|
|
62666
62717
|
var openBreaks = keepCorners ?
|
|
62667
|
-
findInteriorCorners(t, channels, n, false, getCornerParams(tol)) : [];
|
|
62718
|
+
findInteriorCorners(t, channels, n, false, getCornerParams(tol, ctx.cornerBias)) : [];
|
|
62668
62719
|
return smoothOpenSpans(origX, origY, t, channels, n, openBreaks, ctx);
|
|
62669
62720
|
}
|
|
62670
62721
|
|
|
@@ -62676,9 +62727,9 @@ ${svg}
|
|
|
62676
62727
|
var bounds = [0].concat(interiorBreaks);
|
|
62677
62728
|
bounds.push(n - 1);
|
|
62678
62729
|
if (ctx.keepCorners && bounds.length > 2) {
|
|
62679
|
-
bounds = refineBounds(t, channels, bounds, getCornerParams(ctx.tol));
|
|
62730
|
+
bounds = refineBounds(t, channels, bounds, getCornerParams(ctx.tol, ctx.cornerBias));
|
|
62680
62731
|
}
|
|
62681
|
-
var params = ctx.keepCorners ? getCornerParams(ctx.tol) : null;
|
|
62732
|
+
var params = ctx.keepCorners ? getCornerParams(ctx.tol, ctx.cornerBias) : null;
|
|
62682
62733
|
var xx = [], yy = [];
|
|
62683
62734
|
for (var s = 0; s < bounds.length - 1; s++) {
|
|
62684
62735
|
var lo = bounds[s], hi = bounds[s + 1];
|
|
@@ -62864,7 +62915,7 @@ ${svg}
|
|
|
62864
62915
|
// "Output resampling" note above). Step 1 evaluates the smoother at a uniform
|
|
62865
62916
|
// dense step; step 2 makes one forward pass keeping the endpoints plus every
|
|
62866
62917
|
// interior vertex where the accumulated turn since the last kept vertex reaches
|
|
62867
|
-
//
|
|
62918
|
+
// the bend-angle threshold, or where the sagitta guard trips. @inputCount bounds the dense
|
|
62868
62919
|
// sampling (and thus the output). Returns one array per channel, ordered by
|
|
62869
62920
|
// increasing arc length, including both endpoints.
|
|
62870
62921
|
function sampleSmoothedCurve(src, a, b, closed, ctx, inputCount) {
|
|
@@ -62873,7 +62924,7 @@ ${svg}
|
|
|
62873
62924
|
var maxPoints = Math.max(inputCount, MIN_CLOSED_SEGMENTS) * MAX_OUTPUT_FACTOR;
|
|
62874
62925
|
|
|
62875
62926
|
// 1. dense uniform sampling of the smoothed curve
|
|
62876
|
-
var nDense = Math.ceil(span /
|
|
62927
|
+
var nDense = Math.ceil(span / ctx.denseStep) + 1;
|
|
62877
62928
|
if (nDense < MIN_CLOSED_SEGMENTS + 1) nDense = MIN_CLOSED_SEGMENTS + 1;
|
|
62878
62929
|
if (nDense > maxPoints) nDense = maxPoints;
|
|
62879
62930
|
if (nDense < 2) nDense = 2;
|
|
@@ -62883,7 +62934,7 @@ ${svg}
|
|
|
62883
62934
|
}
|
|
62884
62935
|
|
|
62885
62936
|
// 2. one-pass bend-angle filter
|
|
62886
|
-
var theta =
|
|
62937
|
+
var theta = ctx.bendAngle;
|
|
62887
62938
|
var epsDev = ctx.tol * DEVIATION_FACTOR;
|
|
62888
62939
|
var out = [];
|
|
62889
62940
|
for (var c = 0; c < K; c++) out.push([]);
|
|
@@ -63180,6 +63231,20 @@ ${svg}
|
|
|
63180
63231
|
if (opts.gain !== undefined && opts.gain !== null && !(opts.gain >= 0)) {
|
|
63181
63232
|
stop$1('Expected gain to be a number >= 0');
|
|
63182
63233
|
}
|
|
63234
|
+
if (opts.max_bend_angle !== undefined && opts.max_bend_angle !== null &&
|
|
63235
|
+
!(opts.max_bend_angle > 0)) {
|
|
63236
|
+
stop$1('Expected max-bend-angle to be a number > 0 (degrees)');
|
|
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;
|
|
63183
63248
|
var implicitlySmoothedNames = getImplicitlyTargetedLayerNames(dataset, targetLayers, layerHasPaths);
|
|
63184
63249
|
|
|
63185
63250
|
// Smoothing rewrites coordinates, so lock in any pending (non-destructive)
|
|
@@ -63197,6 +63262,7 @@ ${svg}
|
|
|
63197
63262
|
var before = arcs.getPointCount();
|
|
63198
63263
|
filterDetailPaths(arcs, {
|
|
63199
63264
|
distance: tolerance,
|
|
63265
|
+
tortuosity: opts.prefilter_gate,
|
|
63200
63266
|
spherical: spherical
|
|
63201
63267
|
});
|
|
63202
63268
|
var removed = before - arcs.getPointCount();
|
|
@@ -63209,8 +63275,10 @@ ${svg}
|
|
|
63209
63275
|
tolerance: tolerance,
|
|
63210
63276
|
method: method,
|
|
63211
63277
|
spherical: spherical,
|
|
63212
|
-
keepCorners:
|
|
63213
|
-
|
|
63278
|
+
keepCorners: keepCorners,
|
|
63279
|
+
cornerBias: opts.corner_bias,
|
|
63280
|
+
gain: opts.gain,
|
|
63281
|
+
maxBendAngle: opts.max_bend_angle
|
|
63214
63282
|
});
|
|
63215
63283
|
|
|
63216
63284
|
if (implicitlySmoothedNames.length > 0) {
|
|
@@ -63236,7 +63304,9 @@ ${svg}
|
|
|
63236
63304
|
method: opts.method,
|
|
63237
63305
|
spherical: opts.spherical,
|
|
63238
63306
|
keepCorners: opts.keepCorners,
|
|
63307
|
+
cornerBias: opts.cornerBias,
|
|
63239
63308
|
gain: opts.gain,
|
|
63309
|
+
maxBendAngle: opts.maxBendAngle,
|
|
63240
63310
|
closed: arcs.arcIsClosed(arcId)
|
|
63241
63311
|
});
|
|
63242
63312
|
nn.push(res.xx.length);
|
|
@@ -65053,7 +65123,7 @@ ${svg}
|
|
|
65053
65123
|
return name == 'rectangle' || name == 'rectangles' || name == 'filter' && opts.cleanup;
|
|
65054
65124
|
}
|
|
65055
65125
|
|
|
65056
|
-
var version = "0.7.
|
|
65126
|
+
var version = "0.7.33";
|
|
65057
65127
|
|
|
65058
65128
|
// Parse command line args into commands and run them
|
|
65059
65129
|
// 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
|
@@ -32930,14 +32930,30 @@ ${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'
|
|
32940
32936
|
})
|
|
32937
|
+
.option('max-bend-angle', {
|
|
32938
|
+
describe: 'max bend between output segments in degrees (default is 8)',
|
|
32939
|
+
type: 'number'
|
|
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
|
+
})
|
|
32941
32957
|
.option('planar', {
|
|
32942
32958
|
// describe: 'smooth decimal degree coords in 2D space (default is spherical)',
|
|
32943
32959
|
type: 'flag'
|
|
@@ -57264,7 +57280,7 @@ ${svg}
|
|
|
57264
57280
|
// Returns {xx: [], yy: []}. Arc endpoints are always preserved, so shared
|
|
57265
57281
|
// topology nodes stay put and the operation is topology-safe like -simplify.
|
|
57266
57282
|
var DEFAULT_WEIGHTING = 0.7;
|
|
57267
|
-
var DEFAULT_TORTUOSITY =
|
|
57283
|
+
var DEFAULT_TORTUOSITY = 4;
|
|
57268
57284
|
// How far (in detail-distances of arc length) the survivor-merge pass looks ahead
|
|
57269
57285
|
// for a chord that closes a convoluted excursion. Bounds the pass to O(n) and
|
|
57270
57286
|
// caps how long a thin spike it can slice in one merge.
|
|
@@ -62341,7 +62357,8 @@ ${svg}
|
|
|
62341
62357
|
useSphericalSimplify: useSphericalSimplify
|
|
62342
62358
|
});
|
|
62343
62359
|
|
|
62344
|
-
// Structural-corner detection for -smooth's
|
|
62360
|
+
// Structural-corner detection for -smooth's corner preservation (on by default;
|
|
62361
|
+
// disabled with no-corners or corner-bias=0).
|
|
62345
62362
|
//
|
|
62346
62363
|
// Many boundaries alternate between natural, freely-curving stretches (coast,
|
|
62347
62364
|
// river centerline) and artificial straight-line segments (state/county
|
|
@@ -62377,14 +62394,18 @@ ${svg}
|
|
|
62377
62394
|
var MIN_RUN_LEN_FACTOR = 1.0; // a structural run must be at least tol * this long
|
|
62378
62395
|
var MIN_RUN_RADIUS_FACTOR = 1.0; // and bend no tighter than radius tol * this
|
|
62379
62396
|
|
|
62380
|
-
|
|
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;
|
|
62381
62402
|
return {
|
|
62382
62403
|
tol: tol,
|
|
62383
62404
|
cornerAngle: CORNER_ANGLE,
|
|
62384
62405
|
tangentWindow: TANGENT_WINDOW_FACTOR * tol,
|
|
62385
62406
|
innerWindow: INNER_WINDOW_FACTOR * TANGENT_WINDOW_FACTOR * tol,
|
|
62386
62407
|
concentration: CORNER_CONCENTRATION,
|
|
62387
|
-
minRunLen: MIN_RUN_LEN_FACTOR * tol,
|
|
62408
|
+
minRunLen: MIN_RUN_LEN_FACTOR * tol / bias,
|
|
62388
62409
|
maxTurnRate: 1 / (MIN_RUN_RADIUS_FACTOR * tol) // radians of turning per ground unit
|
|
62389
62410
|
};
|
|
62390
62411
|
}
|
|
@@ -62587,20 +62608,25 @@ ${svg}
|
|
|
62587
62608
|
// chord * accumulatedTurn / 8 estimates the bow of a circular arc, and we also
|
|
62588
62609
|
// cut when it exceeds a fraction of the tolerance. Both tests are O(1) per dense
|
|
62589
62610
|
// vertex, so the pass stays O(n).
|
|
62590
|
-
var DENSE_STEP_FACTOR = 0.033; // dense sampling step = tolerance * this
|
|
62591
|
-
// resolve the sharpest
|
|
62592
|
-
// ~ the kernel scale)
|
|
62593
|
-
// angle filter can reach
|
|
62594
|
-
//
|
|
62595
|
-
// kept well under
|
|
62596
|
-
//
|
|
62597
|
-
|
|
62611
|
+
var DENSE_STEP_FACTOR = 0.033; // dense sampling step = tolerance * this at the
|
|
62612
|
+
// default bend angle. Must resolve the sharpest
|
|
62613
|
+
// smoothed feature (radius ~ the kernel scale)
|
|
62614
|
+
// finely enough that the angle filter can reach
|
|
62615
|
+
// the bend-angle joins: one dense segment turns
|
|
62616
|
+
// ~ this/0.4 radians there, kept well under the
|
|
62617
|
+
// bend angle so the discrete accumulation barely
|
|
62618
|
+
// overshoots the threshold. For a smaller-than-
|
|
62619
|
+
// default bend angle the step is refined in
|
|
62620
|
+
// proportion so the threshold stays reachable.
|
|
62621
|
+
var DEFAULT_BEND_ANGLE = 8 * Math.PI / 180; // keep a vertex after this much accumulated
|
|
62622
|
+
// turn (max turn between consecutive output
|
|
62623
|
+
// segments); user-overridable via max-bend-angle
|
|
62598
62624
|
var DEVIATION_FACTOR = 0.1; // sagitta guard: also cut a gentle bend that bows
|
|
62599
62625
|
// more than tolerance * this from its chord
|
|
62600
62626
|
|
|
62601
62627
|
// Smooth a single arc's coordinates.
|
|
62602
62628
|
// @xx, @yy: coordinate arrays (may be typed-array subarrays) for one arc.
|
|
62603
|
-
// @opts: {tolerance, method, spherical, closed, keepCorners}
|
|
62629
|
+
// @opts: {tolerance, method, spherical, closed, keepCorners, gain, maxBendAngle}
|
|
62604
62630
|
// Returns {xx: [], yy: []} with the smoothed coordinates. Endpoints of open
|
|
62605
62631
|
// arcs are preserved exactly (so shared topology nodes stay put); closed arcs
|
|
62606
62632
|
// are smoothed cyclically and returned closed (first point repeated at the end).
|
|
@@ -62615,6 +62641,24 @@ ${svg}
|
|
|
62615
62641
|
return g >= 0 ? g : 0;
|
|
62616
62642
|
}
|
|
62617
62643
|
|
|
62644
|
+
// Resolve the output bend-angle threshold from the user option (in degrees) to
|
|
62645
|
+
// radians. It caps the turn between consecutive output segments: a larger angle
|
|
62646
|
+
// keeps fewer vertices (coarser joins), a smaller one keeps more (smoother joins).
|
|
62647
|
+
// Non-positive or missing values fall back to the default.
|
|
62648
|
+
function resolveBendAngle(opts) {
|
|
62649
|
+
var deg = opts.maxBendAngle;
|
|
62650
|
+
if (deg === undefined || deg === null || !(deg > 0)) return DEFAULT_BEND_ANGLE;
|
|
62651
|
+
return deg * Math.PI / 180;
|
|
62652
|
+
}
|
|
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
|
+
|
|
62618
62662
|
function smoothArcCoords(xx, yy, opts) {
|
|
62619
62663
|
var n = xx.length;
|
|
62620
62664
|
var origX = toArray(xx);
|
|
@@ -62627,12 +62671,19 @@ ${svg}
|
|
|
62627
62671
|
var closed = !!opts.closed;
|
|
62628
62672
|
var spherical = !!opts.spherical;
|
|
62629
62673
|
var keepCorners = !!opts.keepCorners;
|
|
62674
|
+
var bendAngle = resolveBendAngle(opts);
|
|
62630
62675
|
var ctx = {
|
|
62631
62676
|
tol: tol,
|
|
62632
62677
|
method: method,
|
|
62633
62678
|
spherical: spherical,
|
|
62634
62679
|
keepCorners: keepCorners,
|
|
62680
|
+
cornerBias: resolveCornerBias(opts),
|
|
62635
62681
|
gain: resolveGain(opts),
|
|
62682
|
+
bendAngle: bendAngle,
|
|
62683
|
+
// Refine the dense step for a smaller-than-default bend angle so one dense
|
|
62684
|
+
// segment still turns well under the threshold; never coarsen it beyond the
|
|
62685
|
+
// default (the angle filter alone thins the output for larger angles).
|
|
62686
|
+
denseStep: tol * DENSE_STEP_FACTOR * Math.min(1, bendAngle / DEFAULT_BEND_ANGLE),
|
|
62636
62687
|
radius: tol * WINDOW_RADIUS_FACTOR,
|
|
62637
62688
|
scale: (method == 'gaussian' ? GAUSSIAN_SIGMA_FACTOR : PAEK_SCALE_FACTOR) * tol
|
|
62638
62689
|
};
|
|
@@ -62647,7 +62698,7 @@ ${svg}
|
|
|
62647
62698
|
|
|
62648
62699
|
if (closed) {
|
|
62649
62700
|
var corners = keepCorners ?
|
|
62650
|
-
findInteriorCorners(t, channels, n, true, getCornerParams(tol)) : [];
|
|
62701
|
+
findInteriorCorners(t, channels, n, true, getCornerParams(tol, ctx.cornerBias)) : [];
|
|
62651
62702
|
if (corners.length === 0) {
|
|
62652
62703
|
return smoothClosedCyclic(t, channels, n, ctx);
|
|
62653
62704
|
}
|
|
@@ -62664,7 +62715,7 @@ ${svg}
|
|
|
62664
62715
|
}
|
|
62665
62716
|
|
|
62666
62717
|
var openBreaks = keepCorners ?
|
|
62667
|
-
findInteriorCorners(t, channels, n, false, getCornerParams(tol)) : [];
|
|
62718
|
+
findInteriorCorners(t, channels, n, false, getCornerParams(tol, ctx.cornerBias)) : [];
|
|
62668
62719
|
return smoothOpenSpans(origX, origY, t, channels, n, openBreaks, ctx);
|
|
62669
62720
|
}
|
|
62670
62721
|
|
|
@@ -62676,9 +62727,9 @@ ${svg}
|
|
|
62676
62727
|
var bounds = [0].concat(interiorBreaks);
|
|
62677
62728
|
bounds.push(n - 1);
|
|
62678
62729
|
if (ctx.keepCorners && bounds.length > 2) {
|
|
62679
|
-
bounds = refineBounds(t, channels, bounds, getCornerParams(ctx.tol));
|
|
62730
|
+
bounds = refineBounds(t, channels, bounds, getCornerParams(ctx.tol, ctx.cornerBias));
|
|
62680
62731
|
}
|
|
62681
|
-
var params = ctx.keepCorners ? getCornerParams(ctx.tol) : null;
|
|
62732
|
+
var params = ctx.keepCorners ? getCornerParams(ctx.tol, ctx.cornerBias) : null;
|
|
62682
62733
|
var xx = [], yy = [];
|
|
62683
62734
|
for (var s = 0; s < bounds.length - 1; s++) {
|
|
62684
62735
|
var lo = bounds[s], hi = bounds[s + 1];
|
|
@@ -62864,7 +62915,7 @@ ${svg}
|
|
|
62864
62915
|
// "Output resampling" note above). Step 1 evaluates the smoother at a uniform
|
|
62865
62916
|
// dense step; step 2 makes one forward pass keeping the endpoints plus every
|
|
62866
62917
|
// interior vertex where the accumulated turn since the last kept vertex reaches
|
|
62867
|
-
//
|
|
62918
|
+
// the bend-angle threshold, or where the sagitta guard trips. @inputCount bounds the dense
|
|
62868
62919
|
// sampling (and thus the output). Returns one array per channel, ordered by
|
|
62869
62920
|
// increasing arc length, including both endpoints.
|
|
62870
62921
|
function sampleSmoothedCurve(src, a, b, closed, ctx, inputCount) {
|
|
@@ -62873,7 +62924,7 @@ ${svg}
|
|
|
62873
62924
|
var maxPoints = Math.max(inputCount, MIN_CLOSED_SEGMENTS) * MAX_OUTPUT_FACTOR;
|
|
62874
62925
|
|
|
62875
62926
|
// 1. dense uniform sampling of the smoothed curve
|
|
62876
|
-
var nDense = Math.ceil(span /
|
|
62927
|
+
var nDense = Math.ceil(span / ctx.denseStep) + 1;
|
|
62877
62928
|
if (nDense < MIN_CLOSED_SEGMENTS + 1) nDense = MIN_CLOSED_SEGMENTS + 1;
|
|
62878
62929
|
if (nDense > maxPoints) nDense = maxPoints;
|
|
62879
62930
|
if (nDense < 2) nDense = 2;
|
|
@@ -62883,7 +62934,7 @@ ${svg}
|
|
|
62883
62934
|
}
|
|
62884
62935
|
|
|
62885
62936
|
// 2. one-pass bend-angle filter
|
|
62886
|
-
var theta =
|
|
62937
|
+
var theta = ctx.bendAngle;
|
|
62887
62938
|
var epsDev = ctx.tol * DEVIATION_FACTOR;
|
|
62888
62939
|
var out = [];
|
|
62889
62940
|
for (var c = 0; c < K; c++) out.push([]);
|
|
@@ -63180,6 +63231,20 @@ ${svg}
|
|
|
63180
63231
|
if (opts.gain !== undefined && opts.gain !== null && !(opts.gain >= 0)) {
|
|
63181
63232
|
stop$1('Expected gain to be a number >= 0');
|
|
63182
63233
|
}
|
|
63234
|
+
if (opts.max_bend_angle !== undefined && opts.max_bend_angle !== null &&
|
|
63235
|
+
!(opts.max_bend_angle > 0)) {
|
|
63236
|
+
stop$1('Expected max-bend-angle to be a number > 0 (degrees)');
|
|
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;
|
|
63183
63248
|
var implicitlySmoothedNames = getImplicitlyTargetedLayerNames(dataset, targetLayers, layerHasPaths);
|
|
63184
63249
|
|
|
63185
63250
|
// Smoothing rewrites coordinates, so lock in any pending (non-destructive)
|
|
@@ -63197,6 +63262,7 @@ ${svg}
|
|
|
63197
63262
|
var before = arcs.getPointCount();
|
|
63198
63263
|
filterDetailPaths(arcs, {
|
|
63199
63264
|
distance: tolerance,
|
|
63265
|
+
tortuosity: opts.prefilter_gate,
|
|
63200
63266
|
spherical: spherical
|
|
63201
63267
|
});
|
|
63202
63268
|
var removed = before - arcs.getPointCount();
|
|
@@ -63209,8 +63275,10 @@ ${svg}
|
|
|
63209
63275
|
tolerance: tolerance,
|
|
63210
63276
|
method: method,
|
|
63211
63277
|
spherical: spherical,
|
|
63212
|
-
keepCorners:
|
|
63213
|
-
|
|
63278
|
+
keepCorners: keepCorners,
|
|
63279
|
+
cornerBias: opts.corner_bias,
|
|
63280
|
+
gain: opts.gain,
|
|
63281
|
+
maxBendAngle: opts.max_bend_angle
|
|
63214
63282
|
});
|
|
63215
63283
|
|
|
63216
63284
|
if (implicitlySmoothedNames.length > 0) {
|
|
@@ -63236,7 +63304,9 @@ ${svg}
|
|
|
63236
63304
|
method: opts.method,
|
|
63237
63305
|
spherical: opts.spherical,
|
|
63238
63306
|
keepCorners: opts.keepCorners,
|
|
63307
|
+
cornerBias: opts.cornerBias,
|
|
63239
63308
|
gain: opts.gain,
|
|
63309
|
+
maxBendAngle: opts.maxBendAngle,
|
|
63240
63310
|
closed: arcs.arcIsClosed(arcId)
|
|
63241
63311
|
});
|
|
63242
63312
|
nn.push(res.xx.length);
|
|
@@ -65053,7 +65123,7 @@ ${svg}
|
|
|
65053
65123
|
return name == 'rectangle' || name == 'rectangles' || name == 'filter' && opts.cleanup;
|
|
65054
65124
|
}
|
|
65055
65125
|
|
|
65056
|
-
var version = "0.7.
|
|
65126
|
+
var version = "0.7.33";
|
|
65057
65127
|
|
|
65058
65128
|
// Parse command line args into commands and run them
|
|
65059
65129
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|