mapshaper 0.6.112 → 0.6.113
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 +386 -197
- package/package.json +3 -2
- package/www/basemap.js +6 -4
- package/www/elements.css +1 -1
- package/www/images/eye3.png +0 -0
- package/www/index.html +27 -8
- package/www/mapshaper-gui.js +227 -56
- package/www/mapshaper.js +386 -197
- package/www/modules.js +147 -0
- package/www/page.css +71 -34
package/www/mapshaper.js
CHANGED
|
@@ -2107,13 +2107,13 @@
|
|
|
2107
2107
|
|
|
2108
2108
|
// TODO: remove this constant, use actual data from dataset CRS,
|
|
2109
2109
|
// also consider using ellipsoidal formulas where greater accuracy might be important.
|
|
2110
|
-
var R$
|
|
2110
|
+
var R$2 = WGS84.SEMIMAJOR_AXIS;
|
|
2111
2111
|
var D2R = Math.PI / 180;
|
|
2112
2112
|
var R2D = 180 / Math.PI;
|
|
2113
2113
|
|
|
2114
2114
|
// Equirectangular projection
|
|
2115
2115
|
function degreesToMeters(deg) {
|
|
2116
|
-
return deg * D2R * R$
|
|
2116
|
+
return deg * D2R * R$2;
|
|
2117
2117
|
}
|
|
2118
2118
|
|
|
2119
2119
|
function distance3D(ax, ay, az, bx, by, bz) {
|
|
@@ -2210,7 +2210,8 @@
|
|
|
2210
2210
|
lat1 *= D2R;
|
|
2211
2211
|
lat2 *= D2R;
|
|
2212
2212
|
var y = Math.sin(lng2-lng1) * Math.cos(lat2),
|
|
2213
|
-
x = Math.cos(lat1)*Math.sin(lat2) -
|
|
2213
|
+
x = Math.cos(lat1) * Math.sin(lat2) -
|
|
2214
|
+
Math.sin(lat1) * Math.cos(lat2) * Math.cos(lng2-lng1);
|
|
2214
2215
|
return Math.atan2(y, x);
|
|
2215
2216
|
}
|
|
2216
2217
|
|
|
@@ -2270,9 +2271,9 @@
|
|
|
2270
2271
|
lng *= D2R;
|
|
2271
2272
|
lat *= D2R;
|
|
2272
2273
|
cosLat = Math.cos(lat);
|
|
2273
|
-
p[0] = Math.cos(lng) * cosLat * R$
|
|
2274
|
-
p[1] = Math.sin(lng) * cosLat * R$
|
|
2275
|
-
p[2] = Math.sin(lat) * R$
|
|
2274
|
+
p[0] = Math.cos(lng) * cosLat * R$2;
|
|
2275
|
+
p[1] = Math.sin(lng) * cosLat * R$2;
|
|
2276
|
+
p[2] = Math.sin(lat) * R$2;
|
|
2276
2277
|
}
|
|
2277
2278
|
|
|
2278
2279
|
// Haversine formula (well conditioned at small distances)
|
|
@@ -2291,7 +2292,7 @@
|
|
|
2291
2292
|
function greatCircleDistance(lng1, lat1, lng2, lat2) {
|
|
2292
2293
|
var D2R = Math.PI / 180,
|
|
2293
2294
|
dist = sphericalDistance(lng1 * D2R, lat1 * D2R, lng2 * D2R, lat2 * D2R);
|
|
2294
|
-
return dist * R$
|
|
2295
|
+
return dist * R$2;
|
|
2295
2296
|
}
|
|
2296
2297
|
|
|
2297
2298
|
|
|
@@ -2389,7 +2390,7 @@
|
|
|
2389
2390
|
var Geom = /*#__PURE__*/Object.freeze({
|
|
2390
2391
|
__proto__: null,
|
|
2391
2392
|
D2R: D2R,
|
|
2392
|
-
R: R$
|
|
2393
|
+
R: R$2,
|
|
2393
2394
|
R2D: R2D,
|
|
2394
2395
|
bearing: bearing,
|
|
2395
2396
|
bearing2D: bearing2D,
|
|
@@ -16948,47 +16949,6 @@
|
|
|
16948
16949
|
splitPathByIds: splitPathByIds
|
|
16949
16950
|
});
|
|
16950
16951
|
|
|
16951
|
-
// TODO: also delete positive-space rings nested inside holes
|
|
16952
|
-
function deleteHoles(lyr, arcs) {
|
|
16953
|
-
editShapes(lyr.shapes, function(path) {
|
|
16954
|
-
if (geom.getPathArea(path, arcs) <= 0) {
|
|
16955
|
-
return null; // null deletes the path
|
|
16956
|
-
}
|
|
16957
|
-
});
|
|
16958
|
-
}
|
|
16959
|
-
|
|
16960
|
-
// Returns a function that separates rings in a polygon into space-enclosing rings
|
|
16961
|
-
// and holes. Also fixes self-intersections.
|
|
16962
|
-
//
|
|
16963
|
-
function getHoleDivider(nodes, spherical) {
|
|
16964
|
-
var split = getSelfIntersectionSplitter(nodes);
|
|
16965
|
-
// var split = internal.getSelfIntersectionSplitter_v1(nodes); console.log('split')
|
|
16966
|
-
|
|
16967
|
-
return function(rings, cw, ccw) {
|
|
16968
|
-
var pathArea = spherical ? geom.getSphericalPathArea : geom.getPlanarPathArea;
|
|
16969
|
-
forEachShapePart(rings, function(ringIds) {
|
|
16970
|
-
var splitRings = split(ringIds);
|
|
16971
|
-
if (splitRings.length === 0) {
|
|
16972
|
-
debug("[getRingDivider()] Defective path:", ringIds);
|
|
16973
|
-
}
|
|
16974
|
-
splitRings.forEach(function(ringIds, i) {
|
|
16975
|
-
var ringArea = pathArea(ringIds, nodes.arcs);
|
|
16976
|
-
if (ringArea > 0) {
|
|
16977
|
-
cw.push(ringIds);
|
|
16978
|
-
} else if (ringArea < 0) {
|
|
16979
|
-
ccw.push(ringIds);
|
|
16980
|
-
}
|
|
16981
|
-
});
|
|
16982
|
-
});
|
|
16983
|
-
};
|
|
16984
|
-
}
|
|
16985
|
-
|
|
16986
|
-
var PolygonHoles = /*#__PURE__*/Object.freeze({
|
|
16987
|
-
__proto__: null,
|
|
16988
|
-
deleteHoles: deleteHoles,
|
|
16989
|
-
getHoleDivider: getHoleDivider
|
|
16990
|
-
});
|
|
16991
|
-
|
|
16992
16952
|
// Remap any references to duplicate arcs in paths to use the same arcs
|
|
16993
16953
|
// Remove any unused arcs from the dataset's ArcCollection.
|
|
16994
16954
|
// Return a NodeCollection
|
|
@@ -17593,6 +17553,47 @@
|
|
|
17593
17553
|
return idx;
|
|
17594
17554
|
}
|
|
17595
17555
|
|
|
17556
|
+
// TODO: also delete positive-space rings nested inside holes
|
|
17557
|
+
function deleteHoles(lyr, arcs) {
|
|
17558
|
+
editShapes(lyr.shapes, function(path) {
|
|
17559
|
+
if (geom.getPathArea(path, arcs) <= 0) {
|
|
17560
|
+
return null; // null deletes the path
|
|
17561
|
+
}
|
|
17562
|
+
});
|
|
17563
|
+
}
|
|
17564
|
+
|
|
17565
|
+
// Returns a function that separates rings in a polygon into space-enclosing rings
|
|
17566
|
+
// and holes. Also fixes self-intersections.
|
|
17567
|
+
//
|
|
17568
|
+
function getHoleDivider(nodes, spherical) {
|
|
17569
|
+
var split = getSelfIntersectionSplitter(nodes);
|
|
17570
|
+
// var split = internal.getSelfIntersectionSplitter_v1(nodes); console.log('split')
|
|
17571
|
+
|
|
17572
|
+
return function(rings, cw, ccw) {
|
|
17573
|
+
var pathArea = spherical ? geom.getSphericalPathArea : geom.getPlanarPathArea;
|
|
17574
|
+
forEachShapePart(rings, function(ringIds) {
|
|
17575
|
+
var splitRings = split(ringIds);
|
|
17576
|
+
if (splitRings.length === 0) {
|
|
17577
|
+
debug("[getRingDivider()] Defective path:", ringIds);
|
|
17578
|
+
}
|
|
17579
|
+
splitRings.forEach(function(ringIds, i) {
|
|
17580
|
+
var ringArea = pathArea(ringIds, nodes.arcs);
|
|
17581
|
+
if (ringArea > 0) {
|
|
17582
|
+
cw.push(ringIds);
|
|
17583
|
+
} else if (ringArea < 0) {
|
|
17584
|
+
ccw.push(ringIds);
|
|
17585
|
+
}
|
|
17586
|
+
});
|
|
17587
|
+
});
|
|
17588
|
+
};
|
|
17589
|
+
}
|
|
17590
|
+
|
|
17591
|
+
var PolygonHoles = /*#__PURE__*/Object.freeze({
|
|
17592
|
+
__proto__: null,
|
|
17593
|
+
deleteHoles: deleteHoles,
|
|
17594
|
+
getHoleDivider: getHoleDivider
|
|
17595
|
+
});
|
|
17596
|
+
|
|
17596
17597
|
// Associate mosaic tiles with shapes (i.e. identify the groups of tiles that
|
|
17597
17598
|
// belong to each shape)
|
|
17598
17599
|
//
|
|
@@ -17701,7 +17702,6 @@
|
|
|
17701
17702
|
function MosaicIndex(lyr, nodes, optsArg) {
|
|
17702
17703
|
var opts = optsArg || {};
|
|
17703
17704
|
var shapes = lyr.shapes;
|
|
17704
|
-
getHoleDivider(nodes);
|
|
17705
17705
|
var mosaic = buildPolygonMosaic(nodes).mosaic;
|
|
17706
17706
|
// map arc ids to tile ids
|
|
17707
17707
|
var arcTileIndex = new ShapeArcIndex(mosaic, nodes.arcs);
|
|
@@ -31076,7 +31076,7 @@ ${svg}
|
|
|
31076
31076
|
rewindPolygonParts: rewindPolygonParts
|
|
31077
31077
|
});
|
|
31078
31078
|
|
|
31079
|
-
function
|
|
31079
|
+
function dissolveBufferDataset2(dataset, optsArg) {
|
|
31080
31080
|
var opts = optsArg || {};
|
|
31081
31081
|
var lyr = dataset.layers[0];
|
|
31082
31082
|
var tmp;
|
|
@@ -31084,6 +31084,55 @@ ${svg}
|
|
|
31084
31084
|
return; // raw offset path
|
|
31085
31085
|
}
|
|
31086
31086
|
var nodes = addIntersectionCuts(dataset, {rebuild_topology: true});
|
|
31087
|
+
var mosaicIndex = new MosaicIndex(lyr, nodes, {flat: false, no_holes: false});
|
|
31088
|
+
|
|
31089
|
+
// rewindPolygonParts(lyr, nodes);
|
|
31090
|
+
lyr.shapes = lyr.shapes.map(function(shp, i) {
|
|
31091
|
+
var tiles = mosaicIndex.getTilesByShapeIds([i]);
|
|
31092
|
+
if (!tiles.length) return null;
|
|
31093
|
+
return tiles.reduce(function(memo, tile) {
|
|
31094
|
+
return memo.concat(tile);
|
|
31095
|
+
}, []);
|
|
31096
|
+
});
|
|
31097
|
+
|
|
31098
|
+
if (opts.debug_winding) {
|
|
31099
|
+
return;
|
|
31100
|
+
}
|
|
31101
|
+
|
|
31102
|
+
if (opts.debug_mosaic) {
|
|
31103
|
+
tmp = composeMosaicLayer(lyr, mosaicIndex.mosaic);
|
|
31104
|
+
lyr.shapes = tmp.shapes;
|
|
31105
|
+
lyr.data = tmp.data;
|
|
31106
|
+
return;
|
|
31107
|
+
}
|
|
31108
|
+
var pathfind = getRingIntersector(mosaicIndex.nodes);
|
|
31109
|
+
var shapes2 = lyr.shapes.map(function(shp, shapeId) {
|
|
31110
|
+
var tiles = mosaicIndex.getTilesByShapeIds([shapeId]);
|
|
31111
|
+
var rings = [];
|
|
31112
|
+
for (var i=0; i<tiles.length; i++) {
|
|
31113
|
+
rings.push(tiles[i][0]);
|
|
31114
|
+
}
|
|
31115
|
+
return pathfind(rings, 'dissolve');
|
|
31116
|
+
});
|
|
31117
|
+
lyr.shapes = shapes2;
|
|
31118
|
+
if (!opts.no_dissolve) {
|
|
31119
|
+
dissolveArcs(dataset);
|
|
31120
|
+
}
|
|
31121
|
+
}
|
|
31122
|
+
|
|
31123
|
+
// TODO: try geodesic option
|
|
31124
|
+
function getIntersectionFunction(crs) {
|
|
31125
|
+
return bufferIntersection$2;
|
|
31126
|
+
}
|
|
31127
|
+
|
|
31128
|
+
function dissolveBufferDataset(dataset, optsArg) {
|
|
31129
|
+
var opts = {};
|
|
31130
|
+
var lyr = dataset.layers[0];
|
|
31131
|
+
var tmp;
|
|
31132
|
+
if (opts.debug_offset) {
|
|
31133
|
+
return; // raw offset path
|
|
31134
|
+
}
|
|
31135
|
+
var nodes = addIntersectionCuts(dataset, {rebuild_topology: true});
|
|
31087
31136
|
if (opts.debug_winding) {
|
|
31088
31137
|
rewindPolygonParts(lyr, nodes);
|
|
31089
31138
|
// debugRingsAndHoles(lyr, nodes);
|
|
@@ -31138,7 +31187,23 @@ ${svg}
|
|
|
31138
31187
|
};
|
|
31139
31188
|
}
|
|
31140
31189
|
|
|
31141
|
-
|
|
31190
|
+
|
|
31191
|
+
function bufferIntersection$2(a, b, c, d) {
|
|
31192
|
+
return bufferIntersection2(a[0], a[1], b[0], b[1], c[0], c[1], d[0], d[1]);
|
|
31193
|
+
}
|
|
31194
|
+
|
|
31195
|
+
// Exclude segments with non-intersecting bounding boxes before
|
|
31196
|
+
// calling intersection function
|
|
31197
|
+
// Possibly slightly faster than direct call... not worth it?
|
|
31198
|
+
function bufferIntersection2(ax, ay, bx, by, cx, cy, dx, dy) {
|
|
31199
|
+
if (ax < cx && ax < dx && bx < cx && bx < dx ||
|
|
31200
|
+
ax > cx && ax > dx && bx > cx && bx > dx ||
|
|
31201
|
+
ay < cy && ay < dy && by < cy && by < dy ||
|
|
31202
|
+
ay > cy && ay > dy && by > cy && by > dy) return null;
|
|
31203
|
+
return segmentIntersection(ax, ay, bx, by, cx, cy, dx, dy);
|
|
31204
|
+
}
|
|
31205
|
+
|
|
31206
|
+
function BufferBuilder(bufferIntersection, opts) {
|
|
31142
31207
|
var self = {};
|
|
31143
31208
|
var buffer, path, insideFlags;
|
|
31144
31209
|
var points = [];
|
|
@@ -31222,26 +31287,18 @@ ${svg}
|
|
|
31222
31287
|
// TODO: consider using a geodetic intersection function for lat-long datasets
|
|
31223
31288
|
// TODO: consider case of an endpoint hit
|
|
31224
31289
|
// TODO: consider case of collinear hit
|
|
31225
|
-
hit = bufferIntersection
|
|
31290
|
+
hit = bufferIntersection(a, b, prevP, p);
|
|
31226
31291
|
if (!hit) {
|
|
31227
31292
|
// continue scanning backward for an intersection
|
|
31228
31293
|
continue;
|
|
31229
31294
|
}
|
|
31230
|
-
|
|
31295
|
+
|
|
31231
31296
|
flagA = insideFlags[idx];
|
|
31232
31297
|
flagB = insideFlags[idx + 1];
|
|
31233
31298
|
if (flagA && flagB) {
|
|
31234
31299
|
// newest segment collides with an interior segment - do not rewind
|
|
31235
31300
|
continue;
|
|
31236
31301
|
}
|
|
31237
|
-
if (prevFlag === false) {
|
|
31238
|
-
// if segment intersects an outside segment from outside the buffer,
|
|
31239
|
-
// we are likely closing a loop,
|
|
31240
|
-
// so we stop backtracking and reset the backtrack limit to avoid
|
|
31241
|
-
// removing the loop
|
|
31242
|
-
backtrackStopIdx = i + 1;
|
|
31243
|
-
break;
|
|
31244
|
-
}
|
|
31245
31302
|
|
|
31246
31303
|
// newest segment collides with an exterior segment
|
|
31247
31304
|
// * assume we're going from inside to outside
|
|
@@ -31282,24 +31339,160 @@ ${svg}
|
|
|
31282
31339
|
return a[0] === b[0] && a[1] === b[1];
|
|
31283
31340
|
}
|
|
31284
31341
|
|
|
31285
|
-
//
|
|
31286
|
-
//
|
|
31287
|
-
//
|
|
31288
|
-
|
|
31289
|
-
|
|
31290
|
-
|
|
31291
|
-
|
|
31292
|
-
|
|
31293
|
-
|
|
31342
|
+
// function countExtendedHits(p0, p1, buffer) {
|
|
31343
|
+
// var bbox = getBbox();
|
|
31344
|
+
// var width = Math.max(bbox[2] - bbox[0], bbox[3] - bbox[1]);
|
|
31345
|
+
// var p2 = [extend(p1[0], p1[0] - p0[0], size), extend(p1[1], p1[1] - p0[1], size)];
|
|
31346
|
+
// var hits = 0;
|
|
31347
|
+
// for (var i=backtrackStopIdx, n = buffer.length-1; i<n; i++) {
|
|
31348
|
+
// if (bufferIntersection(buffer[i], buffer[i+1], p1, p2)) {
|
|
31349
|
+
// hits++;
|
|
31350
|
+
// }
|
|
31351
|
+
// }
|
|
31352
|
+
// return hits;
|
|
31353
|
+
// };
|
|
31354
|
+
|
|
31355
|
+
var R$1 = WGS84.SEMIMAJOR_AXIS;
|
|
31356
|
+
|
|
31357
|
+
// GeographicLib docs: https://geographiclib.sourceforge.io/html/js/
|
|
31358
|
+
// https://geographiclib.sourceforge.io/html/js/module-GeographicLib_Geodesic.Geodesic.html
|
|
31359
|
+
// https://geographiclib.sourceforge.io/html/js/tutorial-2-interface.html
|
|
31360
|
+
function getGeodesic(P) {
|
|
31361
|
+
if (!isLatLngCRS(P)) error('Expected an unprojected CRS');
|
|
31362
|
+
var f = P.es / (1 + Math.sqrt(P.one_es));
|
|
31363
|
+
// var GeographicLib = require('mproj').internal.GeographicLib;
|
|
31364
|
+
var GeographicLib = require$1('geographiclib-geodesic');
|
|
31365
|
+
// return new GeographicLib.Geodesic.Geodesic(P.a, 0)
|
|
31366
|
+
return new GeographicLib.Geodesic.Geodesic(P.a, f);
|
|
31367
|
+
}
|
|
31368
|
+
|
|
31369
|
+
function interpolatePoint2D(ax, ay, bx, by, k) {
|
|
31370
|
+
var j = 1 - k;
|
|
31371
|
+
return [ax * j + bx * k, ay * j + by * k];
|
|
31372
|
+
}
|
|
31373
|
+
|
|
31374
|
+
function getInterpolationFunction(P) {
|
|
31375
|
+
var spherical = P && isLatLngCRS(P);
|
|
31376
|
+
if (!spherical) return interpolatePoint2D;
|
|
31377
|
+
var geod = getGeodesic(P);
|
|
31378
|
+
return function(lng, lat, lng2, lat2, k) {
|
|
31379
|
+
var r = geod.Inverse(lat, lng, lat2, lng2);
|
|
31380
|
+
var dist = r.s12 * k;
|
|
31381
|
+
var r2 = geod.Direct(lat, lng, r.azi1, dist);
|
|
31382
|
+
return [r2.lon2, r2.lat2];
|
|
31383
|
+
};
|
|
31384
|
+
}
|
|
31385
|
+
|
|
31386
|
+
function getPlanarSegmentEndpoint(x, y, bearing, meterDist) {
|
|
31387
|
+
var rad = bearing / 180 * Math.PI;
|
|
31388
|
+
var dx = Math.sin(rad) * meterDist;
|
|
31389
|
+
var dy = Math.cos(rad) * meterDist;
|
|
31390
|
+
return [x + dx, y + dy];
|
|
31294
31391
|
}
|
|
31295
31392
|
|
|
31393
|
+
// source: https://github.com/mapbox/cheap-ruler/blob/master/index.js
|
|
31394
|
+
function fastGeodeticSegmentFunction(lng, lat, bearing, meterDist) {
|
|
31395
|
+
var D2R = Math.PI / 180;
|
|
31396
|
+
var cos = Math.cos(lat * D2R);
|
|
31397
|
+
var cos2 = 2 * cos * cos - 1;
|
|
31398
|
+
var cos3 = 2 * cos * cos2 - cos;
|
|
31399
|
+
var cos4 = 2 * cos * cos3 - cos2;
|
|
31400
|
+
var cos5 = 2 * cos * cos4 - cos3;
|
|
31401
|
+
var kx = (111.41513 * cos - 0.09455 * cos3 + 0.00012 * cos5) * 1000;
|
|
31402
|
+
var ky = (111.13209 - 0.56605 * cos2 + 0.0012 * cos4) * 1000;
|
|
31403
|
+
var bearingRad = bearing * D2R;
|
|
31404
|
+
var lat2 = lat + Math.cos(bearingRad) * meterDist / ky;
|
|
31405
|
+
var lng2 = lng + Math.sin(bearingRad) * meterDist / kx;
|
|
31406
|
+
return [lng2, lat2];
|
|
31407
|
+
}
|
|
31408
|
+
|
|
31409
|
+
function wrap(deg) {
|
|
31410
|
+
while (deg < -180) deg += 360;
|
|
31411
|
+
while (deg > 180) deg -= 360;
|
|
31412
|
+
return deg;
|
|
31413
|
+
}
|
|
31414
|
+
|
|
31415
|
+
function fastGeodeticBearingFunction(lng1, lat1, lng2, lat2) {
|
|
31416
|
+
var D2R = Math.PI / 180;
|
|
31417
|
+
var f = 1 / 298.257223563;
|
|
31418
|
+
var e2 = f * (2 - f);
|
|
31419
|
+
var m = R$1 * D2R;
|
|
31420
|
+
var coslat = Math.cos(lat1 * D2R);
|
|
31421
|
+
var w2 = 1 / (1 - e2 * (1 - coslat * coslat));
|
|
31422
|
+
var w = Math.sqrt(w2);
|
|
31423
|
+
var kx = m * w * coslat;
|
|
31424
|
+
var ky = m * w * w2 * (1 - e2);
|
|
31425
|
+
var dx = wrap(lng2 - lng1) * kx;
|
|
31426
|
+
var dy = (lat2 - lat1) * ky;
|
|
31427
|
+
return Math.atan2(dx, dy) / D2R;
|
|
31428
|
+
}
|
|
31429
|
+
|
|
31430
|
+
function getGeodeticSegmentFunction(P) {
|
|
31431
|
+
if (!isLatLngCRS(P)) {
|
|
31432
|
+
return getPlanarSegmentEndpoint;
|
|
31433
|
+
}
|
|
31434
|
+
var g = getGeodesic(P);
|
|
31435
|
+
return function(lng, lat, bearing, meterDist) {
|
|
31436
|
+
var o = g.Direct(lat, lng, bearing, meterDist);
|
|
31437
|
+
var p = [o.lon2, o.lat2];
|
|
31438
|
+
return p;
|
|
31439
|
+
};
|
|
31440
|
+
}
|
|
31441
|
+
|
|
31442
|
+
function getFastGeodeticSegmentFunction(P) {
|
|
31443
|
+
// CAREFUL: this function has higher error at very large distances and at the poles
|
|
31444
|
+
// also, it wouldn't work for other planets than Earth
|
|
31445
|
+
return isLatLngCRS(P) ? fastGeodeticSegmentFunction : getPlanarSegmentEndpoint;
|
|
31446
|
+
}
|
|
31447
|
+
|
|
31448
|
+
// return function to calculate bearing of a segment in degrees
|
|
31449
|
+
function getBearingFunction(dataset) {
|
|
31450
|
+
var P = getDatasetCRS(dataset);
|
|
31451
|
+
// var g = getGeodesic(P);
|
|
31452
|
+
// if (isLatLngCRS) {
|
|
31453
|
+
// return function(lng1, lat1, lng2, lat2) {
|
|
31454
|
+
// var tmp = g.Inverse(lat1, lng1, lat2, lng2);
|
|
31455
|
+
// return tmp.azi1;
|
|
31456
|
+
// // return bearingDegrees(lng1, lat1, lng2, lat2);
|
|
31457
|
+
// };
|
|
31458
|
+
// }
|
|
31459
|
+
// return isLatLngCRS(P) ? bearingDegrees : bearingDegrees2D;
|
|
31460
|
+
return isLatLngCRS(P) ? fastGeodeticBearingFunction : bearingDegrees2D;
|
|
31461
|
+
}
|
|
31462
|
+
|
|
31463
|
+
// get bearing in degrees from point ab to point cd
|
|
31464
|
+
function bearingDegrees(a, b, c, d) {
|
|
31465
|
+
return geom.bearing(a, b, c, d) * 180 / Math.PI;
|
|
31466
|
+
}
|
|
31467
|
+
|
|
31468
|
+
function bearingDegrees2D(a, b, c, d) {
|
|
31469
|
+
return geom.bearing2D(a, b, c, d) * 180 / Math.PI;
|
|
31470
|
+
}
|
|
31471
|
+
|
|
31472
|
+
var Geodesic = /*#__PURE__*/Object.freeze({
|
|
31473
|
+
__proto__: null,
|
|
31474
|
+
bearingDegrees: bearingDegrees,
|
|
31475
|
+
bearingDegrees2D: bearingDegrees2D,
|
|
31476
|
+
getBearingFunction: getBearingFunction,
|
|
31477
|
+
getFastGeodeticSegmentFunction: getFastGeodeticSegmentFunction,
|
|
31478
|
+
getGeodeticSegmentFunction: getGeodeticSegmentFunction,
|
|
31479
|
+
getInterpolationFunction: getInterpolationFunction,
|
|
31480
|
+
getPlanarSegmentEndpoint: getPlanarSegmentEndpoint,
|
|
31481
|
+
interpolatePoint2D: interpolatePoint2D
|
|
31482
|
+
});
|
|
31483
|
+
|
|
31296
31484
|
// Returns a function for generating GeoJSON MultiPolygon geometries
|
|
31297
|
-
function getPolylineBufferMaker$2(
|
|
31485
|
+
function getPolylineBufferMaker$2(dataset, opts) {
|
|
31298
31486
|
// var sliceLen = opts.slice_length || Infinity;
|
|
31487
|
+
var crs = getDatasetCRS(dataset);
|
|
31488
|
+
var geod = getFastGeodeticSegmentFunction(crs);
|
|
31489
|
+
var bufferIntersection = getIntersectionFunction();
|
|
31490
|
+
var getBearing = getBearingFunction(dataset);
|
|
31299
31491
|
var segsPerQuadrant = opts.arc_quality >= 2 ? opts.arc_quality : 12;
|
|
31492
|
+
var segAngle = 360 / segsPerQuadrant / 4;
|
|
31300
31493
|
var capStyle = opts.cap_style || 'round'; // expect 'round' or 'flat'
|
|
31301
|
-
var pathIter = new ShapeIter(arcs);
|
|
31302
|
-
var builder = new BufferBuilder(opts);
|
|
31494
|
+
var pathIter = new ShapeIter(dataset.arcs);
|
|
31495
|
+
var builder = new BufferBuilder(bufferIntersection, opts);
|
|
31303
31496
|
|
|
31304
31497
|
return function makeBufferGeoJSON(shape, distance) {
|
|
31305
31498
|
var rings = [];
|
|
@@ -31341,14 +31534,17 @@ ${svg}
|
|
|
31341
31534
|
var rings = [];
|
|
31342
31535
|
var x0, y0, x1, y1, x2, y2; // path traversal coords
|
|
31343
31536
|
var p1, p2; // extruded points
|
|
31344
|
-
var
|
|
31537
|
+
var p1Prev, p2Prev;
|
|
31538
|
+
var bearing1, bearing2, bearing2Prev, joinAngle, hit;
|
|
31345
31539
|
var firstBearing;
|
|
31540
|
+
var joinPoints;
|
|
31346
31541
|
var i = 0;
|
|
31347
31542
|
pathIter.init(path);
|
|
31348
31543
|
|
|
31349
31544
|
if (pathIter.hasNext()) {
|
|
31350
31545
|
x0 = x2 = pathIter.x;
|
|
31351
31546
|
y0 = y2 = pathIter.y;
|
|
31547
|
+
builder.addPathVertex([x0, y0]); // start building the path side
|
|
31352
31548
|
i++;
|
|
31353
31549
|
}
|
|
31354
31550
|
|
|
@@ -31358,43 +31554,67 @@ ${svg}
|
|
|
31358
31554
|
debug("skipping a duplicate point");
|
|
31359
31555
|
continue;
|
|
31360
31556
|
}
|
|
31557
|
+
|
|
31361
31558
|
x1 = x2;
|
|
31362
31559
|
y1 = y2;
|
|
31363
31560
|
x2 = pathIter.x;
|
|
31364
31561
|
y2 = pathIter.y;
|
|
31562
|
+
builder.addPathVertex([x2, y2]); // extend path
|
|
31365
31563
|
|
|
31366
|
-
//
|
|
31564
|
+
// bearing (direction) of the segment is slightly different at the first
|
|
31565
|
+
// and second endpoint, using geodesic math
|
|
31367
31566
|
// TODO: no need to calculate twice with planar coordinates
|
|
31368
|
-
prevBearing = bearing2;
|
|
31369
31567
|
bearing1 = getBearing(x1, y1, x2, y2);
|
|
31370
31568
|
bearing2 = getBearing(x2, y2, x1, y1) - 180;
|
|
31569
|
+
// extrude current segment to the left
|
|
31371
31570
|
p1 = geod(x1, y1, bearing1 - 90, dist);
|
|
31372
31571
|
p2 = geod(x2, y2, bearing2 - 90, dist);
|
|
31373
31572
|
|
|
31374
31573
|
if (i == 1) {
|
|
31375
31574
|
firstBearing = bearing1;
|
|
31376
|
-
builder.addPathVertex([x1, y1]);
|
|
31377
31575
|
} else {
|
|
31378
|
-
joinAngle = getJoinAngle(
|
|
31576
|
+
joinAngle = getJoinAngle(bearing2Prev, bearing1);
|
|
31379
31577
|
}
|
|
31380
31578
|
|
|
31381
|
-
|
|
31382
|
-
|
|
31383
|
-
|
|
31384
|
-
builder.
|
|
31579
|
+
// various connections between current extruded segment and prev segment
|
|
31580
|
+
if (i == 1) {
|
|
31581
|
+
// first segment - no join
|
|
31582
|
+
builder.addBufferVertex(p1, false);
|
|
31583
|
+
} else if (joinAngle > segAngle * 1.5) {
|
|
31584
|
+
// round join
|
|
31585
|
+
// builder.addBufferVertex(p2Prev, false) // testing
|
|
31586
|
+
joinPoints = makeOutsideRoundJoin(x1, y1, bearing2Prev - 90, joinAngle, dist);
|
|
31587
|
+
builder.addBufferVertices(joinPoints);
|
|
31588
|
+
// builder.addBufferVertex(p1, false) // testing
|
|
31589
|
+
p1 = joinPoints.pop();
|
|
31590
|
+
} else if (joinAngle > 0 && (hit = elbowJoin(p1Prev, p2Prev, p1, p2)) ||
|
|
31591
|
+
joinAngle < 0 && (hit = bufferIntersection(p1Prev, p2Prev, p1, p2))) {
|
|
31592
|
+
// elbow join (concave or convex)
|
|
31593
|
+
builder.addBufferVertex(hit, false);
|
|
31594
|
+
p1 = hit;
|
|
31595
|
+
} else if (joinAngle == 0) {
|
|
31596
|
+
// collinear segments (can we really skip p2Prev on a sphere?)
|
|
31597
|
+
builder.addBufferVertex(p1, false);
|
|
31598
|
+
} else {
|
|
31599
|
+
// if (joinAngle > 0) {
|
|
31600
|
+
// probably a leftward bend and extruded segments do not intersect
|
|
31601
|
+
// // console.log("UNEXPECTED SEGMENT JOIN")
|
|
31602
|
+
// }
|
|
31603
|
+
builder.addBufferVertex(p2Prev);
|
|
31604
|
+
builder.addBufferVertex(p1, joinAngle < 0);
|
|
31385
31605
|
}
|
|
31386
31606
|
|
|
31387
|
-
|
|
31388
|
-
|
|
31389
|
-
|
|
31390
|
-
// TODO: restore slicing?
|
|
31391
|
-
// if (center.length - 1 >= sliceLen) {
|
|
31392
|
-
// builder.done(rings);
|
|
31393
|
-
// }
|
|
31394
|
-
|
|
31607
|
+
bearing2Prev = bearing2;
|
|
31608
|
+
p1Prev = p1;
|
|
31609
|
+
p2Prev = p2;
|
|
31395
31610
|
i++;
|
|
31396
31611
|
}
|
|
31397
31612
|
|
|
31613
|
+
// TODO: add this to cap and join code below
|
|
31614
|
+
if (p2Prev) {
|
|
31615
|
+
builder.addBufferVertex(p2Prev);
|
|
31616
|
+
}
|
|
31617
|
+
|
|
31398
31618
|
if (x2 == x0 && y2 == y0) { // closed path
|
|
31399
31619
|
// add join to finish closed path
|
|
31400
31620
|
// TODO - figure out which bearing to use
|
|
@@ -31428,6 +31648,68 @@ ${svg}
|
|
|
31428
31648
|
return points;
|
|
31429
31649
|
}
|
|
31430
31650
|
|
|
31651
|
+
// The vertices of this join are outside of the arc that it approximates and
|
|
31652
|
+
// the segments of the join touch the arc at their midpoints.
|
|
31653
|
+
// The first and last of the returned vertices extend the segments on either
|
|
31654
|
+
// side of the join.
|
|
31655
|
+
function makeOutsideRoundJoin(cx, cy, startBearing, arcAngle, dist) {
|
|
31656
|
+
// point count of 1 would be an elbow joint
|
|
31657
|
+
// (elbow joins should be created elsewhere)
|
|
31658
|
+
var pointCount = Math.max(1, Math.round(arcAngle / segAngle));
|
|
31659
|
+
var stepAngle = arcAngle / pointCount;
|
|
31660
|
+
var points = [];
|
|
31661
|
+
var i = 0;
|
|
31662
|
+
var a, b, c, d, joinP, tanP, bearing;
|
|
31663
|
+
while (i <= pointCount) {
|
|
31664
|
+
bearing = startBearing + stepAngle * i;
|
|
31665
|
+
tanP = geod(cx, cy, bearing, dist);
|
|
31666
|
+
c = geod(tanP[0], tanP[1], bearing - 90, dist * 2);
|
|
31667
|
+
d = geod(tanP[0], tanP[1], bearing + 90, dist * 2);
|
|
31668
|
+
if (i > 0) {
|
|
31669
|
+
joinP = bufferIntersection(a, b, c, d);
|
|
31670
|
+
if (!joinP) {
|
|
31671
|
+
throw Error(`no intersection on ${i} of ${pointCount}`);
|
|
31672
|
+
} else {
|
|
31673
|
+
points.push(joinP);
|
|
31674
|
+
}
|
|
31675
|
+
}
|
|
31676
|
+
a = c;
|
|
31677
|
+
b = d;
|
|
31678
|
+
i++;
|
|
31679
|
+
}
|
|
31680
|
+
return points;
|
|
31681
|
+
}
|
|
31682
|
+
|
|
31683
|
+
function elbowJoin(a, b, c, d) {
|
|
31684
|
+
var k = 2 ** 13;
|
|
31685
|
+
var b2 = [extend(b[0], b[0] - a[0], k), extend(b[1], b[1] - a[1], k)];
|
|
31686
|
+
var c2 = [extend(c[0], c[0] - d[0], k), extend(c[1], c[1] - d[1], k)];
|
|
31687
|
+
return bufferIntersection(a, b2, c2, d);
|
|
31688
|
+
}
|
|
31689
|
+
|
|
31690
|
+
|
|
31691
|
+
// function getBbox() {
|
|
31692
|
+
// var lastIdx = buffer.length - 1;
|
|
31693
|
+
// var x, y;
|
|
31694
|
+
// if (!_bbox) {
|
|
31695
|
+
// _bbox = [-Infinity, -Infinity, Infinity, Infinity];
|
|
31696
|
+
// }
|
|
31697
|
+
// while (_idx < lastIdx) {
|
|
31698
|
+
// _idx++;
|
|
31699
|
+
// x = buffer[_idx][0];
|
|
31700
|
+
// y = buffer[_idx][1];
|
|
31701
|
+
// _bbox[0] = Math.min(x, _bbox[0]);
|
|
31702
|
+
// _bbox[1] = Math.min(y, _bbox[1]);
|
|
31703
|
+
// _bbox[2] = Math.max(x, _bbox[2]);
|
|
31704
|
+
// _bbox[3] = Math.max(y, _bbox[3]);
|
|
31705
|
+
// }
|
|
31706
|
+
// return _bbox;
|
|
31707
|
+
// }
|
|
31708
|
+
|
|
31709
|
+
function extend(n, d, k) {
|
|
31710
|
+
return n + d * k;
|
|
31711
|
+
}
|
|
31712
|
+
|
|
31431
31713
|
// get interior vertices of an interpolated CW arc
|
|
31432
31714
|
function makeRoundJoin(cx, cy, startBearing, arcAngle, dist) {
|
|
31433
31715
|
var points = [];
|
|
@@ -31457,12 +31739,14 @@ ${svg}
|
|
|
31457
31739
|
}
|
|
31458
31740
|
|
|
31459
31741
|
// Returns a function for generating GeoJSON MultiPolygon geometries
|
|
31460
|
-
function getPolylineBufferMaker$1(
|
|
31742
|
+
function getPolylineBufferMaker$1(dataset, opts) {
|
|
31743
|
+
var geod = getFastGeodeticSegmentFunction(getDatasetCRS(dataset));
|
|
31744
|
+
var getBearing = getBearingFunction(dataset);
|
|
31461
31745
|
var sliceLen = opts.slice_length || Infinity;
|
|
31462
31746
|
var backtrackSteps = opts.backtrack >= 0 ? opts.backtrack : 100;
|
|
31463
31747
|
var segsPerQuadrant = opts.arc_quality >= 2 ? opts.arc_quality : 12;
|
|
31464
31748
|
var capStyle = opts.cap_style || 'round'; // expect 'round' or 'flat'
|
|
31465
|
-
var pathIter = new ShapeIter(arcs);
|
|
31749
|
+
var pathIter = new ShapeIter(dataset.arcs);
|
|
31466
31750
|
var left, center, rings;
|
|
31467
31751
|
|
|
31468
31752
|
return function makeBufferGeoJSON(shape, distance) {
|
|
@@ -31713,8 +31997,10 @@ ${svg}
|
|
|
31713
31997
|
}
|
|
31714
31998
|
|
|
31715
31999
|
// Returns a function for generating GeoJSON geometries (MultiLineString or MultiPolygon)
|
|
31716
|
-
function getPolylineBufferMaker(
|
|
31717
|
-
var
|
|
32000
|
+
function getPolylineBufferMaker(dataset, opts) {
|
|
32001
|
+
var geod = getFastGeodeticSegmentFunction(getDatasetCRS(dataset));
|
|
32002
|
+
var getBearing = getBearingFunction(dataset);
|
|
32003
|
+
var maker = getPathBufferMaker(dataset.arcs, geod, getBearing, opts);
|
|
31718
32004
|
var geomType = opts.geometry_type;
|
|
31719
32005
|
// polyline output could be used for debugging
|
|
31720
32006
|
var outputGeom = opts.output_geometry == 'polyline' ? 'polyline' : 'polygon';
|
|
@@ -31915,107 +32201,12 @@ ${svg}
|
|
|
31915
32201
|
return geom.segmentIntersection(ax, ay, bx, by, cx, cy, dx, dy);
|
|
31916
32202
|
}
|
|
31917
32203
|
|
|
31918
|
-
// GeographicLib docs: https://geographiclib.sourceforge.io/html/js/
|
|
31919
|
-
// https://geographiclib.sourceforge.io/html/js/module-GeographicLib_Geodesic.Geodesic.html
|
|
31920
|
-
// https://geographiclib.sourceforge.io/html/js/tutorial-2-interface.html
|
|
31921
|
-
function getGeodesic(P) {
|
|
31922
|
-
if (!isLatLngCRS(P)) error('Expected an unprojected CRS');
|
|
31923
|
-
var f = P.es / (1 + Math.sqrt(P.one_es));
|
|
31924
|
-
var GeographicLib = require$1('mproj').internal.GeographicLib;
|
|
31925
|
-
return new GeographicLib.Geodesic.Geodesic(P.a, f);
|
|
31926
|
-
}
|
|
31927
|
-
|
|
31928
|
-
function interpolatePoint2D(ax, ay, bx, by, k) {
|
|
31929
|
-
var j = 1 - k;
|
|
31930
|
-
return [ax * j + bx * k, ay * j + by * k];
|
|
31931
|
-
}
|
|
31932
|
-
|
|
31933
|
-
function getInterpolationFunction(P) {
|
|
31934
|
-
var spherical = P && isLatLngCRS(P);
|
|
31935
|
-
if (!spherical) return interpolatePoint2D;
|
|
31936
|
-
var geod = getGeodesic(P);
|
|
31937
|
-
return function(lng, lat, lng2, lat2, k) {
|
|
31938
|
-
var r = geod.Inverse(lat, lng, lat2, lng2);
|
|
31939
|
-
var dist = r.s12 * k;
|
|
31940
|
-
var r2 = geod.Direct(lat, lng, r.azi1, dist);
|
|
31941
|
-
return [r2.lon2, r2.lat2];
|
|
31942
|
-
};
|
|
31943
|
-
}
|
|
31944
|
-
|
|
31945
|
-
function getPlanarSegmentEndpoint(x, y, bearing, meterDist) {
|
|
31946
|
-
var rad = bearing / 180 * Math.PI;
|
|
31947
|
-
var dx = Math.sin(rad) * meterDist;
|
|
31948
|
-
var dy = Math.cos(rad) * meterDist;
|
|
31949
|
-
return [x + dx, y + dy];
|
|
31950
|
-
}
|
|
31951
|
-
|
|
31952
|
-
// source: https://github.com/mapbox/cheap-ruler/blob/master/index.js
|
|
31953
|
-
function fastGeodeticSegmentFunction(lng, lat, bearing, meterDist) {
|
|
31954
|
-
var D2R = Math.PI / 180;
|
|
31955
|
-
var cos = Math.cos(lat * D2R);
|
|
31956
|
-
var cos2 = 2 * cos * cos - 1;
|
|
31957
|
-
var cos3 = 2 * cos * cos2 - cos;
|
|
31958
|
-
var cos4 = 2 * cos * cos3 - cos2;
|
|
31959
|
-
var cos5 = 2 * cos * cos4 - cos3;
|
|
31960
|
-
var kx = (111.41513 * cos - 0.09455 * cos3 + 0.00012 * cos5) * 1000;
|
|
31961
|
-
var ky = (111.13209 - 0.56605 * cos2 + 0.0012 * cos4) * 1000;
|
|
31962
|
-
var bearingRad = bearing * D2R;
|
|
31963
|
-
var lat2 = lat + Math.cos(bearingRad) * meterDist / ky;
|
|
31964
|
-
var lng2 = lng + Math.sin(bearingRad) * meterDist / kx;
|
|
31965
|
-
return [lng2, lat2];
|
|
31966
|
-
}
|
|
31967
|
-
|
|
31968
|
-
function getGeodeticSegmentFunction(P) {
|
|
31969
|
-
if (!isLatLngCRS(P)) {
|
|
31970
|
-
return getPlanarSegmentEndpoint;
|
|
31971
|
-
}
|
|
31972
|
-
var g = getGeodesic(P);
|
|
31973
|
-
return function(lng, lat, bearing, meterDist) {
|
|
31974
|
-
var o = g.Direct(lat, lng, bearing, meterDist);
|
|
31975
|
-
var p = [o.lon2, o.lat2];
|
|
31976
|
-
return p;
|
|
31977
|
-
};
|
|
31978
|
-
}
|
|
31979
|
-
|
|
31980
|
-
function getFastGeodeticSegmentFunction(P) {
|
|
31981
|
-
// CAREFUL: this function has higher error at very large distances and at the poles
|
|
31982
|
-
// also, it wouldn't work for other planets than Earth
|
|
31983
|
-
return isLatLngCRS(P) ? fastGeodeticSegmentFunction : getPlanarSegmentEndpoint;
|
|
31984
|
-
}
|
|
31985
|
-
|
|
31986
|
-
|
|
31987
|
-
function bearingDegrees(a, b, c, d) {
|
|
31988
|
-
return geom.bearing(a, b, c, d) * 180 / Math.PI;
|
|
31989
|
-
}
|
|
31990
|
-
|
|
31991
|
-
function bearingDegrees2D(a, b, c, d) {
|
|
31992
|
-
return geom.bearing2D(a, b, c, d) * 180 / Math.PI;
|
|
31993
|
-
}
|
|
31994
|
-
|
|
31995
|
-
// return function to calculate bearing of a segment in degrees
|
|
31996
|
-
function getBearingFunction(dataset) {
|
|
31997
|
-
var P = getDatasetCRS(dataset);
|
|
31998
|
-
return isLatLngCRS(P) ? bearingDegrees : bearingDegrees2D;
|
|
31999
|
-
}
|
|
32000
|
-
|
|
32001
|
-
var Geodesic = /*#__PURE__*/Object.freeze({
|
|
32002
|
-
__proto__: null,
|
|
32003
|
-
bearingDegrees: bearingDegrees,
|
|
32004
|
-
bearingDegrees2D: bearingDegrees2D,
|
|
32005
|
-
getBearingFunction: getBearingFunction,
|
|
32006
|
-
getFastGeodeticSegmentFunction: getFastGeodeticSegmentFunction,
|
|
32007
|
-
getGeodeticSegmentFunction: getGeodeticSegmentFunction,
|
|
32008
|
-
getInterpolationFunction: getInterpolationFunction,
|
|
32009
|
-
getPlanarSegmentEndpoint: getPlanarSegmentEndpoint,
|
|
32010
|
-
interpolatePoint2D: interpolatePoint2D
|
|
32011
|
-
});
|
|
32012
|
-
|
|
32013
32204
|
function makePolylineBuffer(lyr, dataset, opts) {
|
|
32014
32205
|
time('buffer');
|
|
32015
32206
|
var geojson = makeShapeBufferGeoJSON(lyr, dataset, opts);
|
|
32016
32207
|
var dataset2 = importGeoJSON(geojson, {});
|
|
32017
32208
|
if (!opts.debug_points) {
|
|
32018
|
-
|
|
32209
|
+
dissolveBufferDataset2(dataset2, opts);
|
|
32019
32210
|
}
|
|
32020
32211
|
timeEnd('buffer');
|
|
32021
32212
|
return dataset2;
|
|
@@ -32024,13 +32215,11 @@ ${svg}
|
|
|
32024
32215
|
function makeShapeBufferGeoJSON(lyr, dataset, opts) {
|
|
32025
32216
|
var distanceFn = getBufferDistanceFunction(lyr, dataset, opts);
|
|
32026
32217
|
// var toleranceFn = getBufferToleranceFunction(dataset, opts);
|
|
32027
|
-
var geod = getFastGeodeticSegmentFunction(getDatasetCRS(dataset));
|
|
32028
|
-
var getBearing = getBearingFunction(dataset);
|
|
32029
32218
|
var makerOpts = Object.assign({geometry_type: lyr.geometry_type}, opts);
|
|
32030
32219
|
var makeShapeBuffer =
|
|
32031
|
-
opts.v2 && getPolylineBufferMaker$1(dataset
|
|
32032
|
-
opts.v3 && getPolylineBufferMaker$2(dataset
|
|
32033
|
-
getPolylineBufferMaker(dataset
|
|
32220
|
+
opts.v2 && getPolylineBufferMaker$1(dataset, makerOpts) ||
|
|
32221
|
+
opts.v3 && getPolylineBufferMaker$2(dataset, makerOpts) ||
|
|
32222
|
+
getPolylineBufferMaker(dataset, makerOpts);
|
|
32034
32223
|
// var records = lyr.data ? lyr.data.getRecords() : null;
|
|
32035
32224
|
var arr = lyr.shapes.reduce(function(memo, shape, i) {
|
|
32036
32225
|
var distance = distanceFn(i);
|
|
@@ -46659,7 +46848,7 @@ ${svg}
|
|
|
46659
46848
|
});
|
|
46660
46849
|
}
|
|
46661
46850
|
|
|
46662
|
-
var version = "0.6.
|
|
46851
|
+
var version = "0.6.113";
|
|
46663
46852
|
|
|
46664
46853
|
// Parse command line args into commands and run them
|
|
46665
46854
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|