mapshaper 0.5.89 → 0.5.93

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/www/mapshaper.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.5.88";
3
+ var VERSION = "0.5.92";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -994,15 +994,23 @@
994
994
  }
995
995
 
996
996
  function copyElements(src, i, dest, j, n, rev) {
997
- if (src === dest && j > i) error ("copy error");
997
+ var same = src == dest || src.buffer && src.buffer == dest.buffer;
998
998
  var inc = 1,
999
- offs = 0;
999
+ offs = 0,
1000
+ k;
1000
1001
  if (rev) {
1002
+ if (same) error('copy error');
1001
1003
  inc = -1;
1002
1004
  offs = n - 1;
1003
1005
  }
1004
- for (var k=0; k<n; k++, offs += inc) {
1005
- dest[k + j] = src[i + offs];
1006
+ if (same && j > i) {
1007
+ for (k=n-1; k>=0; k--) {
1008
+ dest[j + k] = src[i + k];
1009
+ }
1010
+ } else {
1011
+ for (k=0; k<n; k++, offs += inc) {
1012
+ dest[k + j] = src[i + offs];
1013
+ }
1006
1014
  }
1007
1015
  }
1008
1016
 
@@ -1240,7 +1248,8 @@
1240
1248
  // print a message to stdout
1241
1249
  function print() {
1242
1250
  STDOUT = true; // tell logArgs() to print to stdout, not stderr
1243
- message.apply(null, arguments);
1251
+ // calling message() adds the "[command name]" prefix
1252
+ _message(utils.toArray(arguments));
1244
1253
  STDOUT = false;
1245
1254
  }
1246
1255
 
@@ -1755,6 +1764,69 @@
1755
1764
  return [xmin, ymin, xmax, ymax];
1756
1765
  }
1757
1766
 
1767
+ function deleteVertex(arcs, i) {
1768
+ var data = arcs.getVertexData();
1769
+ var nn = data.nn;
1770
+ var n = data.xx.length;
1771
+ // avoid re-allocating memory
1772
+ var xx2 = new Float64Array(data.xx.buffer, 0, n-1);
1773
+ var yy2 = new Float64Array(data.yy.buffer, 0, n-1);
1774
+ var count = 0;
1775
+ var found = false;
1776
+ for (var j=0; j<nn.length; j++) {
1777
+ count += nn[j];
1778
+ if (count >= i && !found) { // TODO: confirm this
1779
+ nn[j] = nn[j] - 1;
1780
+ found = true;
1781
+ }
1782
+ }
1783
+ utils.copyElements(data.xx, 0, xx2, 0, i);
1784
+ utils.copyElements(data.yy, 0, yy2, 0, i);
1785
+ utils.copyElements(data.xx, i+1, xx2, i, n-i-1);
1786
+ utils.copyElements(data.yy, i+1, yy2, i, n-i-1);
1787
+ arcs.updateVertexData(nn, xx2, yy2, null);
1788
+ }
1789
+
1790
+ function insertVertex(arcs, i, p) {
1791
+ // TODO: add extra bytes to the buffers, to reduce new memory allocation
1792
+ var data = arcs.getVertexData();
1793
+ var nn = data.nn;
1794
+ var n = data.xx.length;
1795
+ var count = 0;
1796
+ var found = false;
1797
+ var xx2, yy2;
1798
+ // avoid re-allocating memory on each insertion
1799
+ if (data.xx.buffer.byteLength >= data.xx.length * 8 + 8) {
1800
+ xx2 = new Float64Array(data.xx.buffer, 0, n+1);
1801
+ yy2 = new Float64Array(data.yy.buffer, 0, n+1);
1802
+ } else {
1803
+ xx2 = new Float64Array(new ArrayBuffer((n + 20) * 8), 0, n+1);
1804
+ yy2 = new Float64Array(new ArrayBuffer((n + 20) * 8), 0, n+1);
1805
+ }
1806
+ for (var j=0; j<nn.length; j++) {
1807
+ count += nn[j];
1808
+ if (count >= i && !found) { // TODO: confirm this
1809
+ nn[j] = nn[j] + 1;
1810
+ found = true;
1811
+ }
1812
+ }
1813
+ utils.copyElements(data.xx, 0, xx2, 0, i);
1814
+ utils.copyElements(data.yy, 0, yy2, 0, i);
1815
+ utils.copyElements(data.xx, i, xx2, i+1, n-i);
1816
+ utils.copyElements(data.yy, i, yy2, i+1, n-i);
1817
+ xx2[i] = p[0];
1818
+ yy2[i] = p[1];
1819
+ arcs.updateVertexData(nn, xx2, yy2, null);
1820
+ }
1821
+
1822
+ var ArcUtils = /*#__PURE__*/Object.freeze({
1823
+ __proto__: null,
1824
+ absArcId: absArcId,
1825
+ calcArcBounds: calcArcBounds,
1826
+ deleteVertex: deleteVertex,
1827
+ insertVertex: insertVertex
1828
+ });
1829
+
1758
1830
  var WGS84 = {
1759
1831
  // https://en.wikipedia.org/wiki/Earth_radius
1760
1832
  SEMIMAJOR_AXIS: 6378137,
@@ -2157,6 +2229,7 @@
2157
2229
  function getPointToPathInfo(px, py, ids, arcs) {
2158
2230
  var iter = arcs.getShapeIter(ids);
2159
2231
  var pPathSq = Infinity;
2232
+ var arcId;
2160
2233
  var ax, ay, bx, by, axmin, aymin, bxmin, bymin, pabSq;
2161
2234
  if (iter.hasNext()) {
2162
2235
  ax = axmin = bxmin = iter.x;
@@ -2168,6 +2241,7 @@
2168
2241
  pabSq = pointSegDistSq2(px, py, ax, ay, bx, by);
2169
2242
  if (pabSq < pPathSq) {
2170
2243
  pPathSq = pabSq;
2244
+ arcId = iter._ids[iter._i]; // kludge
2171
2245
  axmin = ax;
2172
2246
  aymin = ay;
2173
2247
  bxmin = bx;
@@ -2179,7 +2253,8 @@
2179
2253
  if (pPathSq == Infinity) return {distance: Infinity};
2180
2254
  return {
2181
2255
  segment: [[axmin, aymin], [bxmin, bymin]],
2182
- distance: Math.sqrt(pPathSq)
2256
+ distance: Math.sqrt(pPathSq),
2257
+ arcId: arcId
2183
2258
  };
2184
2259
  }
2185
2260
 
@@ -2187,11 +2262,20 @@
2187
2262
  // Return unsigned distance of a point to the nearest point on a polygon or polyline path
2188
2263
  //
2189
2264
  function getPointToShapeDistance(x, y, shp, arcs) {
2190
- var minDist = (shp || []).reduce(function(minDist, ids) {
2191
- var pathDist = getPointToPathDistance(x, y, ids, arcs);
2192
- return Math.min(minDist, pathDist);
2193
- }, Infinity);
2194
- return minDist;
2265
+ var info = getPointToShapeInfo(x, y, shp, arcs);
2266
+ return info ? info.distance : Infinity;
2267
+ }
2268
+
2269
+ function getPointToShapeInfo(x, y, shp, arcs) {
2270
+ return (shp || []).reduce(function(memo, ids) {
2271
+ var pathInfo = getPointToPathInfo(x, y, ids, arcs);
2272
+ if (!memo || pathInfo.distance < memo.distance) return pathInfo;
2273
+ return memo;
2274
+ }, null) || {
2275
+ distance: Infinity,
2276
+ arcId: -1,
2277
+ segment: null
2278
+ };
2195
2279
  }
2196
2280
 
2197
2281
  // @ids array of arc ids
@@ -2276,6 +2360,7 @@
2276
2360
  getPointToPathDistance: getPointToPathDistance,
2277
2361
  getPointToPathInfo: getPointToPathInfo,
2278
2362
  getPointToShapeDistance: getPointToShapeDistance,
2363
+ getPointToShapeInfo: getPointToShapeInfo,
2279
2364
  getAvgPathXY: getAvgPathXY,
2280
2365
  getMaxPath: getMaxPath,
2281
2366
  countVerticesInPath: countVerticesInPath,
@@ -4908,6 +4993,7 @@
4908
4993
  this._n = 0;
4909
4994
  this.x = 0;
4910
4995
  this.y = 0;
4996
+ this.i = -1;
4911
4997
  }
4912
4998
 
4913
4999
  ShapeIter.prototype.hasNext = function() {
@@ -4918,6 +5004,7 @@
4918
5004
  if (arc.hasNext()) {
4919
5005
  this.x = arc.x;
4920
5006
  this.y = arc.y;
5007
+ this.i = arc.i;
4921
5008
  return true;
4922
5009
  }
4923
5010
  this.nextArc();
@@ -5376,6 +5463,10 @@
5376
5463
  };
5377
5464
  };
5378
5465
 
5466
+ this.getVertex2 = function(i) {
5467
+ return [_xx[i], _yy[i]];
5468
+ };
5469
+
5379
5470
  // @nth: index of vertex. ~(idx) starts from the opposite endpoint
5380
5471
  this.indexOfVertex = function(arcId, nth) {
5381
5472
  var absId = arcId < 0 ? ~arcId : arcId,
@@ -5480,6 +5571,8 @@
5480
5571
  }
5481
5572
  };
5482
5573
 
5574
+ this.isFlat = function() { return !_zz; };
5575
+
5483
5576
  this.getRetainedInterval = function() {
5484
5577
  return _zlimit;
5485
5578
  };
@@ -9356,6 +9449,18 @@
9356
9449
  };
9357
9450
  addGetters(obj, getters);
9358
9451
  addBBoxGetter(obj, lyr, arcs);
9452
+ obj.field_exists = function(name) {
9453
+ return lyr.data && lyr.data.fieldExists(name) ? true : false;
9454
+ };
9455
+ obj.field_type = function(name) {
9456
+ return lyr.data && getColumnType(name, lyr.data.getRecords()) || null;
9457
+ };
9458
+ obj.field_includes = function(name, val) {
9459
+ if (!lyr.data) return false;
9460
+ return lyr.data.getRecords().some(function(rec) {
9461
+ return rec && (rec[name] === val);
9462
+ });
9463
+ };
9359
9464
  return obj;
9360
9465
  }
9361
9466
 
@@ -20598,6 +20703,10 @@ ${svg}
20598
20703
  .option('target', targetOpt)
20599
20704
  .validate(validateExpressionOpt);
20600
20705
 
20706
+ parser.command('print')
20707
+ .describe('print a message to stdout')
20708
+ .flag('multi_arg');
20709
+
20601
20710
  parser.command('projections')
20602
20711
  .describe('print list of supported projections');
20603
20712
 
@@ -23413,7 +23522,16 @@ ${svg}
23413
23522
  // should be in gui-model.js, moved here for testing
23414
23523
  this.getActiveLayer = function() {
23415
23524
  var targ = (this.getDefaultTargets() || [])[0];
23416
- return targ ? {layer: targ.layers[0], dataset: targ.dataset} : null;
23525
+ // var lyr = targ.layers[0];
23526
+ // Reasons to select the last layer of a multi-layer target:
23527
+ // * This layer was imported last
23528
+ // * This layer is displayed on top of other layers
23529
+ // * This layer is at the top of the layers list
23530
+ // * In TopoJSON input, it makes sense to think of the last object/layer
23531
+ // as the topmost one -- it corresponds to the painter's algorithm and
23532
+ // the way that objects are ordered in SVG.
23533
+ var lyr = targ.layers[targ.layers.length - 1];
23534
+ return targ ? {layer: lyr, dataset: targ.dataset} : null;
23417
23535
  };
23418
23536
 
23419
23537
  function layerObject(lyr, dataset) {
@@ -27150,7 +27268,7 @@ ${svg}
27150
27268
  }
27151
27269
 
27152
27270
  function samePoint(a, b) {
27153
- return a[0] === b[0] && a[1] === b[1];
27271
+ return a && b && a[0] === b[0] && a[1] === b[1];
27154
27272
  }
27155
27273
 
27156
27274
  function isClosedPath(arr) {
@@ -27764,11 +27882,15 @@ ${svg}
27764
27882
  }
27765
27883
 
27766
27884
  function getCategoricalColorScheme(name, n) {
27885
+ var colors;
27767
27886
  initSchemes();
27768
- if (index.categorical.includes(name) === false) {
27769
- stop(name, 'is not a categorical color scheme');
27887
+ if (!isColorSchemeName(name)) {
27888
+ stop('Unknown color scheme name:', name);
27889
+ } else if (isCategoricalColorScheme(name)) {
27890
+ colors = ramps[name] || require('d3-scale-chromatic')['scheme' + name];
27891
+ } else {
27892
+ colors = getColorRamp(name, n);
27770
27893
  }
27771
- var colors = ramps[name] || require('d3-scale-chromatic')['scheme' + name];
27772
27894
  if (n > colors.length) {
27773
27895
  stop(name, 'does not contain', n, 'colors');
27774
27896
  }
@@ -27781,6 +27903,11 @@ ${svg}
27781
27903
  index.diverging.includes(name) || index.rainbow.includes(name);
27782
27904
  }
27783
27905
 
27906
+ function isCategoricalColorScheme(name) {
27907
+ initSchemes();
27908
+ return index.categorical.includes(name);
27909
+ }
27910
+
27784
27911
  function getColorRamp(name, n, stops) {
27785
27912
  initSchemes();
27786
27913
  var lib = require('d3-scale-chromatic');
@@ -28270,7 +28397,7 @@ ${svg}
28270
28397
  };
28271
28398
  }
28272
28399
 
28273
- function getSequentialClassifier$1(classValues, nullValue, dataValues, opts) {
28400
+ function getSequentialClassifier$1(classValues, nullValue, dataValues, method, opts) {
28274
28401
  var numValues = classValues.length;
28275
28402
  var numBuckets = opts.continuous ? numValues - 1 : numValues;
28276
28403
 
@@ -28278,7 +28405,6 @@ ${svg}
28278
28405
  // discreetly classed values
28279
28406
  var numBreaks = numBuckets - 1;
28280
28407
  var round = opts.precision ? getRoundingFunction(opts.precision) : null;
28281
- var method = opts.method || 'quantile';
28282
28408
  var breaks, classifier, dataToClass, classToValue;
28283
28409
 
28284
28410
  if (round) {
@@ -28883,34 +29009,35 @@ ${svg}
28883
29009
  var opts = optsArg || {};
28884
29010
  var records = lyr.data && lyr.data.getRecords();
28885
29011
  var nullValue = opts.null_value || null;
28886
- var looksLikeColors = !!opts.colors || !!opts.color_scheme;
29012
+ var valuesAreColors = !!opts.colors || !!opts.color_scheme;
28887
29013
  var colorScheme;
28888
- var classValues, classifyByValue, classifyById;
28889
- var numBuckets, numValues;
29014
+ var values, classifyByValue, classifyById;
29015
+ var numClasses, numValues;
28890
29016
  var dataField, outputField;
29017
+ var method;
28891
29018
 
28892
29019
  // validate explicitly set classes
28893
29020
  if (opts.classes) {
28894
29021
  if (!utils.isInteger(opts.classes) || opts.classes > 1 === false) {
28895
29022
  stop('Invalid number of classes:', opts.classes, '(expected a value greater than 1)');
28896
29023
  }
28897
- numBuckets = opts.classes;
29024
+ numClasses = opts.classes;
28898
29025
  }
28899
29026
 
28900
29027
  // TODO: better validation of breaks values
28901
29028
  if (opts.breaks) {
28902
- numBuckets = opts.breaks.length + 1;
29029
+ numClasses = opts.breaks.length + 1;
28903
29030
  }
28904
29031
 
28905
29032
  if (opts.index_field) {
28906
29033
  dataField = opts.index_field;
28907
- if (numBuckets > 0 === false) {
29034
+ if (numClasses > 0 === false) {
28908
29035
  stop('The index-field= option requires the classes= option to be set');
28909
29036
  }
28910
29037
  // You can't infer the number of classes by looking at index values;
28911
29038
  // this can cause unwanted interpolation if one or more values are
28912
29039
  // not present in the index field
28913
- // numBuckets = validateClassIndexField(records, opts.index_field);
29040
+ // numClasses = validateClassIndexField(records, opts.index_field);
28914
29041
 
28915
29042
  } else if (opts.field) {
28916
29043
  dataField = opts.field;
@@ -28921,7 +29048,19 @@ ${svg}
28921
29048
  opts.categories = getUniqFieldValues(records, dataField);
28922
29049
  }
28923
29050
 
28924
- if (opts.method == 'non-adjacent') {
29051
+ // get classification method
29052
+ //
29053
+ if (opts.method) {
29054
+ method = opts.method;
29055
+ } else if (opts.categories) {
29056
+ method = 'categorical';
29057
+ } else if (opts.index_field) {
29058
+ method = 'indexed';
29059
+ } else {
29060
+ method = 'quantile'; // TODO: validate data field
29061
+ }
29062
+
29063
+ if (method == 'non-adjacent') {
28925
29064
  if (lyr.geometry_type != 'polygon') {
28926
29065
  stop('The non-adjacent option requires a polygon layer');
28927
29066
  }
@@ -28934,8 +29073,8 @@ ${svg}
28934
29073
  requireDataField(lyr.data, dataField);
28935
29074
  }
28936
29075
 
28937
- if (numBuckets) {
28938
- numValues = opts.continuous ? numBuckets + 1 : numBuckets;
29076
+ if (numClasses) {
29077
+ numValues = opts.continuous ? numClasses + 1 : numClasses;
28939
29078
  }
28940
29079
 
28941
29080
  // support both deprecated color-scheme= option and colors=<color-scheme> syntax
@@ -28950,39 +29089,44 @@ ${svg}
28950
29089
  opts.colors.forEach(parseColor); // validate colors -- error if unparsable
28951
29090
  }
28952
29091
 
29092
+ /// get values (usually colors)
29093
+ ///
28953
29094
  if (colorScheme) {
28954
- // using a named color scheme: generate a ramp
29095
+ if (method == 'non-adjacent') {
29096
+ numClasses = numValues = numClasses || 5;
29097
+ values = getCategoricalColorScheme(colorScheme, numValues);
29098
+
29099
+ } else if (method == 'categorical') {
29100
+ values = getCategoricalColorScheme(colorScheme, opts.categories.length);
29101
+ numClasses = numValues = values.length;
28955
29102
 
28956
- if (opts.categories) {
28957
- classValues = getCategoricalColorScheme(colorScheme, opts.categories.length);
28958
- numBuckets = numValues = classValues.length;
28959
29103
  } else {
28960
- if (!numBuckets) {
29104
+ if (!numClasses) {
28961
29105
  // stop('color-scheme= option requires classes= or breaks=');
28962
- numBuckets = 4; // use a default number of classes
28963
- numValues = opts.continuous ? numBuckets + 1 : numBuckets;
29106
+ numClasses = 4; // use a default number of classes
29107
+ numValues = opts.continuous ? numClasses + 1 : numClasses;
28964
29108
  }
28965
- classValues = getColorRamp(colorScheme, numValues, opts.stops);
29109
+ values = getColorRamp(colorScheme, numValues, opts.stops);
28966
29110
  }
28967
29111
 
28968
29112
  } else if (opts.colors || opts.values) {
28969
- classValues = opts.values ? parseValues(opts.values) : opts.colors;
29113
+ values = opts.values ? parseValues(opts.values) : opts.colors;
28970
29114
  if (!numValues) {
28971
- numValues = classValues.length;
29115
+ numValues = values.length;
28972
29116
  }
28973
- if ((classValues.length != numValues || opts.stops) && numValues > 1) {
29117
+ if ((values.length != numValues || opts.stops) && numValues > 1) {
28974
29118
  // TODO: handle numValues == 1
28975
29119
  // TODO: check for non-interpolatable value types (e.g. boolean, text)
28976
- classValues = interpolateValuesToClasses(classValues, numValues, opts.stops);
29120
+ values = interpolateValuesToClasses(values, numValues, opts.stops);
28977
29121
  }
28978
29122
 
28979
29123
  } else if (numValues > 1) {
28980
29124
  // no values were given: assign indexes for each class
28981
- classValues = getIndexValues(numValues);
29125
+ values = getIndexValues(numValues);
28982
29126
  nullValue = -1;
28983
29127
  }
28984
29128
 
28985
- if (looksLikeColors) {
29129
+ if (valuesAreColors) {
28986
29130
  nullValue = nullValue || '#eee';
28987
29131
  }
28988
29132
 
@@ -28991,24 +29135,24 @@ ${svg}
28991
29135
  }
28992
29136
 
28993
29137
  if (opts.invert) {
28994
- classValues = classValues.concat().reverse();
29138
+ values = values.concat().reverse();
28995
29139
  }
28996
29140
 
28997
- if (looksLikeColors) {
28998
- message('Colors:', formatValuesForLogging(classValues));
29141
+ if (valuesAreColors) {
29142
+ message('Colors:', formatValuesForLogging(values));
28999
29143
  }
29000
29144
 
29001
29145
  // get a function to convert input data to class indexes
29002
29146
  //
29003
- if (opts.method == 'non-adjacent') {
29004
- classifyById = getNonAdjacentClassifier(lyr, dataset, classValues);
29147
+ if (method == 'non-adjacent') {
29148
+ classifyById = getNonAdjacentClassifier(lyr, dataset, values);
29005
29149
  } else if (opts.index_field) {
29006
29150
  // data is pre-classified... just read the index from a field
29007
- classifyByValue = getIndexedClassifier(classValues, nullValue, opts);
29008
- } else if (opts.categories) {
29009
- classifyByValue = getCategoricalClassifier(classValues, nullValue, opts);
29151
+ classifyByValue = getIndexedClassifier(values, nullValue, opts);
29152
+ } else if (method == 'categorical') {
29153
+ classifyByValue = getCategoricalClassifier(values, nullValue, opts);
29010
29154
  } else {
29011
- classifyByValue = getSequentialClassifier$1(classValues, nullValue, getFieldValues(records, dataField), opts);
29155
+ classifyByValue = getSequentialClassifier$1(values, nullValue, getFieldValues(records, dataField), method, opts);
29012
29156
  }
29013
29157
 
29014
29158
  if (classifyByValue) {
@@ -29021,7 +29165,7 @@ ${svg}
29021
29165
 
29022
29166
  // get the name of the output field
29023
29167
  //
29024
- if (looksLikeColors) {
29168
+ if (valuesAreColors) {
29025
29169
  outputField = lyr.geometry_type == 'polyline' ? 'stroke' : 'fill';
29026
29170
  } else {
29027
29171
  outputField = 'class';
@@ -34908,16 +35052,7 @@ ${svg}
34908
35052
  return findVertexIds(p2.x, p2.y, arcs);
34909
35053
  }
34910
35054
 
34911
- // Given a location @p (e.g. corresponding to the mouse pointer location),
34912
- // find the midpoint of two vertices on @shp suitable for inserting a new vertex,
34913
- // but only if:
34914
- // 1. point @p is closer to the midpoint than either adjacent vertex
34915
- // 2. the segment containing @p is longer than a minimum distance in pixels.
34916
- //
34917
- function findInsertionPoint(p, shp, arcs, pixelSize) {
34918
- var p2 = findNearestVertex(p[0], p[1], shp, arcs);
34919
35055
 
34920
- }
34921
35056
 
34922
35057
  function snapVerticesToPoint(ids, p, arcs, final) {
34923
35058
  ids.forEach(function(idx) {
@@ -34998,7 +35133,7 @@ ${svg}
34998
35133
  function findNearestVertex(x, y, shp, arcs, spherical) {
34999
35134
  var calcLen = spherical ? geom.greatCircleDistance : geom.distance2D,
35000
35135
  minLen = Infinity,
35001
- minX, minY, dist, iter;
35136
+ minX, minY, vId, dist, iter;
35002
35137
  for (var i=0; i<shp.length; i++) {
35003
35138
  iter = arcs.getShapeIter(shp[i]);
35004
35139
  while (iter.hasNext()) {
@@ -35007,16 +35142,31 @@ ${svg}
35007
35142
  minLen = dist;
35008
35143
  minX = iter.x;
35009
35144
  minY = iter.y;
35145
+ vId = iter.i;
35010
35146
  }
35011
35147
  }
35012
35148
  }
35013
- return minLen < Infinity ? {x: minX, y: minY} : null;
35149
+ return minLen < Infinity ? {x: minX, y: minY, i: vId} : null;
35150
+ }
35151
+
35152
+ // v: vertex in {x, y, i} format
35153
+ function findAdjacentVertex(v, shp, arcs, offs) {
35154
+ var p, i;
35155
+ var arcEnd = offs == 1 && vertexIsArcEnd(v.i, arcs);
35156
+ var arcStart = offs == -1 && vertexIsArcStart(v.i, arcs);
35157
+ if (arcEnd || arcStart) return null;
35158
+ i = v.i + offs;
35159
+ p = getVertexCoords(i, arcs);
35160
+ return {
35161
+ i: i,
35162
+ x: p[0],
35163
+ y: p[1]
35164
+ };
35014
35165
  }
35015
35166
 
35016
35167
  var VertexUtils = /*#__PURE__*/Object.freeze({
35017
35168
  __proto__: null,
35018
35169
  findNearestVertices: findNearestVertices,
35019
- findInsertionPoint: findInsertionPoint,
35020
35170
  snapVerticesToPoint: snapVerticesToPoint,
35021
35171
  snapPointToArcEndpoint: snapPointToArcEndpoint,
35022
35172
  findVertexIds: findVertexIds,
@@ -35024,7 +35174,8 @@ ${svg}
35024
35174
  vertexIsArcEnd: vertexIsArcEnd,
35025
35175
  vertexIsArcStart: vertexIsArcStart,
35026
35176
  setVertexCoords: setVertexCoords,
35027
- findNearestVertex: findNearestVertex
35177
+ findNearestVertex: findNearestVertex,
35178
+ findAdjacentVertex: findAdjacentVertex
35028
35179
  });
35029
35180
 
35030
35181
  // Returns x,y coordinates of the point that is at the midpoint of each polyline feature
@@ -36633,6 +36784,10 @@ ${svg}
36633
36784
  };
36634
36785
  }
36635
36786
 
36787
+ cmd.print = function(msgArg) {
36788
+ print(msgArg || '');
36789
+ };
36790
+
36636
36791
  cmd.renameLayers = function(layers, names, catalog) {
36637
36792
  if (names && names.join('').indexOf('=') > -1) {
36638
36793
  renameByAssignment(names, catalog);
@@ -39140,7 +39295,7 @@ ${svg}
39140
39295
  }
39141
39296
  if (!(name == 'graticule' || name == 'i' || name == 'help' ||
39142
39297
  name == 'point-grid' || name == 'shape' || name == 'rectangle' ||
39143
- name == 'include')) {
39298
+ name == 'include' || name == 'print')) {
39144
39299
  throw new UserError("No data is available");
39145
39300
  }
39146
39301
  }
@@ -39325,6 +39480,9 @@ ${svg}
39325
39480
  } else if (name == 'polygons') {
39326
39481
  outputLayers = cmd.polygons(targetLayers, targetDataset, opts);
39327
39482
 
39483
+ } else if (name == 'print') {
39484
+ cmd.print(command._.join(' '));
39485
+
39328
39486
  } else if (name == 'proj') {
39329
39487
  initProjLibrary(opts, function() {
39330
39488
  var err = null;
@@ -40202,6 +40360,7 @@ ${svg}
40202
40360
  AnchorPoints,
40203
40361
  ArcClassifier,
40204
40362
  ArcDissolve,
40363
+ ArcUtils,
40205
40364
  Bbox2Clipping,
40206
40365
  BinArray$1,
40207
40366
  BufferCommon,