mapshaper 0.6.38 → 0.6.39

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
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.6.38";
3
+ var VERSION = "0.6.39";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -65,7 +65,7 @@
65
65
  get rtrim () { return rtrim; },
66
66
  get addThousandsSep () { return addThousandsSep; },
67
67
  get numToStr () { return numToStr; },
68
- get formatNumber () { return formatNumber; },
68
+ get formatNumber () { return formatNumber$1; },
69
69
  get formatIntlNumber () { return formatIntlNumber; },
70
70
  get formatNumberForDisplay () { return formatNumberForDisplay; },
71
71
  get shuffle () { return shuffle; },
@@ -649,12 +649,12 @@
649
649
  return decimals >= 0 ? num.toFixed(decimals) : String(num);
650
650
  }
651
651
 
652
- function formatNumber(val) {
652
+ function formatNumber$1(val) {
653
653
  return val + '';
654
654
  }
655
655
 
656
656
  function formatIntlNumber(val) {
657
- var str = formatNumber(val);
657
+ var str = formatNumber$1(val);
658
658
  return '"' + str.replace('.', ',') + '"'; // need to quote if comma-delimited
659
659
  }
660
660
 
@@ -1247,7 +1247,8 @@
1247
1247
 
1248
1248
  // Handle an error caused by invalid input or misuse of API
1249
1249
  function stop() {
1250
- _stop.apply(null, utils.toArray(arguments));
1250
+ // _stop.apply(null, utils.toArray(arguments));
1251
+ _stop.apply(null, messageArgs(arguments));
1251
1252
  }
1252
1253
 
1253
1254
  function interrupt() {
@@ -4670,12 +4671,11 @@
4670
4671
  albersusa: AlbersUSA
4671
4672
  };
4672
4673
 
4673
- // This stub is replaced when loaded in GUI, which may need to load some files
4674
- function initProjLibrary(opts, done) {
4675
- if (!asyncLoader) return done();
4676
- asyncLoader(opts, done);
4674
+ async function initProjLibrary(opts) {
4675
+ if (asyncLoader) await asyncLoader(opts);
4677
4676
  }
4678
4677
 
4678
+ // used by web UI to support loading projection assets asyncronously
4679
4679
  function setProjectionLoader(loader) {
4680
4680
  asyncLoader = loader;
4681
4681
  }
@@ -13115,6 +13115,105 @@
13115
13115
  });
13116
13116
  }
13117
13117
 
13118
+ // Parse a formatted value in DMS DM or D to a numeric value. Returns NaN if unparsable.
13119
+ // Delimiters: degrees: D|d|°; minutes: '; seconds: "
13120
+ function parseDMS(str, fmt) {
13121
+ var defaultRxp = /^(?<prefix>[nsew+-]?)(?<d>[0-9.]+)[d°]? ?(?<m>[0-9.]*)['′]? ?(?<s>[0-9.]*)["″]? ?(?<suffix>[nsew]?)$/i;
13122
+ var rxp = fmt ? getParseRxp(fmt) : defaultRxp;
13123
+ var match = rxp.exec(str.trim());
13124
+ var d = NaN;
13125
+ var deg, min, sec;
13126
+ if (match) {
13127
+ deg = match.groups.d || '0';
13128
+ min = match.groups.m || '0';
13129
+ sec = match.groups.s || '0';
13130
+ d = (+deg) + (+min) / 60 + (+sec) / 3600;
13131
+ if (/[sw-]/i.test(match.groups.prefix || '') || /[sw]/i.test(match.groups.suffix || '')) {
13132
+ d = -d;
13133
+ }
13134
+ }
13135
+ return d;
13136
+ }
13137
+
13138
+ var cache$1 = {};
13139
+
13140
+ function getParseRxp(fmt) {
13141
+ if (fmt in cache$1) return cache$1[fmt];
13142
+ var rxp = fmt;
13143
+ rxp = rxp.replace('[-]', '(?<prefix>-)?'); // optional -
13144
+ rxp = rxp.replace(/\[[NSEW, +-]{2,}\]/, '(?<prefix>$&)');
13145
+ rxp = rxp.replace(/(MM?)(\.M+)?/, (m, g1, g2) => {
13146
+ var s = g1.length == 1 ? '[0-9]+' : '[0-9][0-9]';
13147
+ if (g2) s += `\\.[0-9]+`;
13148
+ return `(?<m>${s})`;
13149
+ });
13150
+ rxp = rxp.replace(/(SS?)(\.S+)?/, (m, g1, g2) => {
13151
+ var s = g1.length == 1 ? '[0-9]+' : '[0-9][0-9]';
13152
+ if (g2) s += `\\.[0-9]+`;
13153
+ return `(?<s>${s})`;
13154
+ });
13155
+ rxp = rxp.replace(/D+/, '(?<d>[0-9]+)');
13156
+ rxp = '^' + rxp + '$';
13157
+ try {
13158
+ // TODO: make sure all DMS codes have been matched
13159
+ cache$1[fmt] = new RegExp(rxp);
13160
+ } catch(e) {
13161
+ stop('Invalid DMS format string:', fmt);
13162
+ }
13163
+ return cache$1[fmt];
13164
+ }
13165
+
13166
+ function formatNumber(val, integers, decimals) {
13167
+ var str = val.toFixed(decimals);
13168
+ var parts = str.split('.');
13169
+ if (parts.length > 0) {
13170
+ parts[0] = parts[0].padStart(integers, '0');
13171
+ str = parts.join('.');
13172
+ }
13173
+ return str;
13174
+ }
13175
+
13176
+ function getDecimals(fmt) {
13177
+ var match = /S\.(S+)/.exec(fmt) || /M\.(M+)/.exec(fmt) || null;
13178
+ return match ? match[1].length : 0;
13179
+ }
13180
+
13181
+ // TODO: support DD.DDDDD
13182
+ function formatDMS(coord, fmt) {
13183
+ if (!fmt) fmt = '[-]D°M\'S.SSS';
13184
+ var str = fmt;
13185
+ var dstr, mstr, sstr;
13186
+ var match = /(D+)[^M]*(M+)[^S[\]]*(S+)?/.exec(fmt);
13187
+ if (!match) {
13188
+ stop('Invalid DMS format string:', fmt);
13189
+ }
13190
+ var gotSeconds = !!match[3];
13191
+ var decimals = getDecimals(fmt);
13192
+ var integers = gotSeconds ? match[3].length : match[2].length;
13193
+ var RES = Math.pow(10, decimals);
13194
+ var CONV = gotSeconds ? 3600 * RES : 60 * RES;
13195
+ var r = Math.floor(Math.abs(coord) * CONV + 0.5);
13196
+ var lastPart = formatNumber((r / RES) % 60, integers, decimals);
13197
+ if (gotSeconds) {
13198
+ r = Math.floor(r / (RES * 60));
13199
+ sstr = lastPart;
13200
+ mstr = String(r % 60).padStart(match[2].length, '0');
13201
+ } else {
13202
+ r = Math.floor(r / RES);
13203
+ mstr = lastPart;
13204
+ sstr = '';
13205
+ }
13206
+ dstr = String(Math.floor(r / 60)).padStart(match[1].length, '0');
13207
+ str = str.replace(/\[-\]/, s => coord < 0 ? '-' : '');
13208
+ str = str.replace(/\[[+-]+\]/, s => coord < 0 ? '-' : '+');
13209
+ str = str.replace(/\[[NS, ]+\]/, s => coord < 0 ? 'S' : 'N');
13210
+ str = str.replace(/\[[EW, ]+\]/, s => coord < 0 ? 'W' : 'E');
13211
+ str = str.replace(/D+/, dstr);
13212
+ str = str.replace(/M+(\.M+)?/, mstr);
13213
+ if (gotSeconds) str = str.replace(/S+(\.S+)?/, sstr);
13214
+ return str;
13215
+ }
13216
+
13118
13217
  function cleanExpression(exp) {
13119
13218
  // workaround for problem in GNU Make v4: end-of-line backslashes inside
13120
13219
  // quoted strings are left in the string (other shell environments remove them)
@@ -13126,7 +13225,9 @@
13126
13225
  round: roundToDigits2,
13127
13226
  int_median: interpolated_median,
13128
13227
  sprintf: utils.format,
13129
- blend: blend
13228
+ blend: blend,
13229
+ format_dms: formatDMS,
13230
+ parse_dms: parseDMS
13130
13231
  });
13131
13232
  }
13132
13233
 
@@ -22791,7 +22892,6 @@ ${svg}
22791
22892
 
22792
22893
  this.getHelpMessage = function(cmdName) {
22793
22894
  var helpCommands, singleCommand, lines;
22794
-
22795
22895
  if (cmdName) {
22796
22896
  singleCommand = findCommandDefn(cmdName, getCommands());
22797
22897
  if (!singleCommand) {
@@ -22910,10 +23010,6 @@ ${svg}
22910
23010
  }
22911
23011
  };
22912
23012
 
22913
- this.printHelp = function(command) {
22914
- print(this.getHelpMessage(command));
22915
- };
22916
-
22917
23013
  function getCommands() {
22918
23014
  return _commands.map(function(cmd) {
22919
23015
  return cmd.done();
@@ -23633,7 +23729,7 @@ ${svg}
23633
23729
  type: 'flag'
23634
23730
  })
23635
23731
  .option('other', {
23636
- describe: 'default color for categorical scheme (defaults to no-data color)'
23732
+ describe: 'default color for categorical scheme (default is nodata color)'
23637
23733
  })
23638
23734
  .option('nodata', {
23639
23735
  describe: 'color to use for invalid or missing data (default is white)'
@@ -24561,7 +24657,7 @@ ${svg}
24561
24657
  parser.command('symbols')
24562
24658
  .describe('symbolize points as arrows, circles, stars, polygons, etc.')
24563
24659
  .option('type', {
24564
- describe: 'symbol type (e.g. arrow, circle, square, star, polygon, ring)'
24660
+ describe: 'types: arrow, circle, square, star, polygon, ring'
24565
24661
  })
24566
24662
  .option('stroke', {})
24567
24663
  .option('stroke-width', {})
@@ -24575,8 +24671,7 @@ ${svg}
24575
24671
  describe: 'symbol line width (linear symbols only)'
24576
24672
  })
24577
24673
  .option('opacity', {
24578
- describe: 'symbol opacity',
24579
- type: 'number'
24674
+ describe: 'symbol opacity'
24580
24675
  })
24581
24676
  .option('geographic', {
24582
24677
  old_alias: 'polygons',
@@ -24678,7 +24773,6 @@ ${svg}
24678
24773
  .option('no-replace', noReplaceOpt);
24679
24774
  // .option('name', nameOpt);
24680
24775
 
24681
-
24682
24776
  parser.command('target')
24683
24777
  .describe('set active layer (or layers)')
24684
24778
  .option('target', {
@@ -24688,6 +24782,14 @@ ${svg}
24688
24782
  .option('type', {
24689
24783
  describe: 'type of layer to target (polygon|polyline|point)'
24690
24784
  })
24785
+ // .option('combine', {
24786
+ // type: 'flag',
24787
+ // describe: 'place all targeted layers in one dataset together with any associated layers'
24788
+ // })
24789
+ // .option('isolate', {
24790
+ // type: 'flag',
24791
+ // describe: 'place all targeted layers in one dataset exclusive of associated layers'
24792
+ // })
24691
24793
  .option('name', {
24692
24794
  describe: 'rename the target layer'
24693
24795
  });
@@ -38520,6 +38622,11 @@ ${svg}
38520
38622
  };
38521
38623
  }
38522
38624
 
38625
+ cmd.printHelp = function(opts) {
38626
+ var str = getOptionParser().getHelpMessage(opts.command);
38627
+ print(str);
38628
+ };
38629
+
38523
38630
  function resetControlFlow(job) {
38524
38631
  job.control = null;
38525
38632
  }
@@ -39159,25 +39266,6 @@ ${svg}
39159
39266
  };
39160
39267
  }
39161
39268
 
39162
- // Parse a formatted value in DMS DM or D to a numeric value. Returns NaN if unparsable.
39163
- // Delimiters: degrees: D|d|°; minutes: '; seconds: "
39164
- function parseDMS(str) {
39165
- var rxp = /^([nsew+-]?)([0-9.]+)[d°]? ?([0-9.]*)['′]? ?([0-9.]*)["″]? ?([nsew]?)$/i;
39166
- var match = rxp.exec(str.trim());
39167
- var d = NaN;
39168
- var deg, min, sec;
39169
- if (match) {
39170
- deg = match[2] || '0';
39171
- min = match[3] || '0';
39172
- sec = match[4] || '0';
39173
- d = (+deg) + (+min) / 60 + (+sec) / 3600;
39174
- if (/[sw-]/i.test(match[1]) || /[sw]/i.test(match[5])) {
39175
- d = -d;
39176
- }
39177
- }
39178
- return d;
39179
- }
39180
-
39181
39269
  function findNearestVertices(p, shp, arcs) {
39182
39270
  var p2 = findNearestVertex(p[0], p[1], shp, arcs);
39183
39271
  return findVertexIds(p2.x, p2.y, arcs);
@@ -42827,9 +42915,41 @@ ${svg}
42827
42915
  // TODO: improve this
42828
42916
  targets[0].layers[0].name = opts.name;
42829
42917
  }
42918
+ if (opts.combine) {
42919
+ targets = combineTargets(targets, catalog);
42920
+ } else if (opts.isolate) {
42921
+ targets = isolateTargets(targets, catalog);
42922
+ }
42830
42923
  catalog.setDefaultTargets(targets);
42831
42924
  };
42832
42925
 
42926
+ function combineTargets(targets, catalog) {
42927
+ var datasets = [];
42928
+ var layers = [];
42929
+ targets.forEach(function(o) {
42930
+ datasets.push(o.dataset);
42931
+ catalog.removeDataset(o.dataset);
42932
+ layers = layers.concat(o.layers);
42933
+ });
42934
+ var combined = mergeDatasets(datasets);
42935
+ catalog.addDataset(combined);
42936
+ return [{
42937
+ dataset: combined,
42938
+ layers: layers
42939
+ }];
42940
+ }
42941
+
42942
+ function isolateTargets(targets, catalog) {
42943
+ var datasets = [];
42944
+ targets.forEach(function(o) {
42945
+ datasets.push(o.dataset);
42946
+ o.layers.forEach(function(lyr) {
42947
+ catalog.removeLayer(lyr, o.dataset);
42948
+
42949
+ });
42950
+ });
42951
+ }
42952
+
42833
42953
  cmd.union = function(targetLayers, targetDataset, opts) {
42834
42954
  if (targetLayers.length < 2) {
42835
42955
  stop('Command requires at least two target layers');
@@ -43214,7 +43334,7 @@ ${svg}
43214
43334
  function commandAcceptsMultipleTargetDatasets(name) {
43215
43335
  return name == 'rotate' || name == 'info' || name == 'proj' ||
43216
43336
  name == 'drop' || name == 'target' || name == 'if' || name == 'elif' ||
43217
- name == 'else' || name == 'endif' || name == 'run';
43337
+ name == 'else' || name == 'endif' || name == 'run' || name == 'i';
43218
43338
  }
43219
43339
 
43220
43340
  function commandAcceptsEmptyTarget(name) {
@@ -43403,8 +43523,8 @@ ${svg}
43403
43523
  job.catalog.addDataset(cmd.graticule(targetDataset, opts));
43404
43524
 
43405
43525
  } else if (name == 'help') {
43406
- // placing this here to handle errors from invalid command names
43407
- getOptionParser().printHelp(command.options.command);
43526
+ // placing help command here to handle errors from invalid command names
43527
+ cmd.printHelp(command.options);
43408
43528
 
43409
43529
  } else if (name == 'i') {
43410
43530
  if (opts.replace) job.catalog = new Catalog(); // is this what we want?
@@ -43486,7 +43606,7 @@ ${svg}
43486
43606
  cmd.print(command._.join(' '));
43487
43607
 
43488
43608
  } else if (name == 'proj') {
43489
- await utils.promisify(initProjLibrary)(opts);
43609
+ await initProjLibrary(opts);
43490
43610
  job.resumeCommand();
43491
43611
  targets.forEach(function(targ) {
43492
43612
  cmd.proj(targ.dataset, job.catalog, opts);
@@ -44321,6 +44441,7 @@ ${svg}
44321
44441
  Heap,
44322
44442
  NodeCollection,
44323
44443
  parseDMS,
44444
+ formatDMS,
44324
44445
  PathIndex,
44325
44446
  PolygonIndex,
44326
44447
  ShpReader,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mapshaper",
3
- "version": "0.6.38",
3
+ "version": "0.6.39",
4
4
  "description": "A tool for editing vector datasets for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
@@ -2479,42 +2479,18 @@
2479
2479
  });
2480
2480
  }
2481
2481
 
2482
+ internal.setProjectionLoader(loadProjLibs);
2483
+
2482
2484
  // load Proj.4 CRS definition files dynamically
2483
2485
  //
2484
- internal.setProjectionLoader(function(opts, done) {
2486
+ async function loadProjLibs(opts) {
2485
2487
  var mproj = require('mproj');
2486
2488
  var libs = internal.findProjLibs([opts.init || '', opts.match || '', opts.crs || ''].join(' '));
2487
- // skip loaded libs
2488
- libs = libs.filter(function(name) {return !mproj.internal.mproj_search_libcache(name);});
2489
- loadProjLibs(libs, done);
2490
- });
2491
-
2492
- function loadProjLibs(libs, done) {
2493
- var mproj = require('mproj');
2494
- var i = 0;
2495
- next();
2496
-
2497
- function next() {
2498
- var libName = libs[i];
2499
- var content, req;
2500
- if (!libName) return done();
2501
- req = new XMLHttpRequest();
2502
- req.addEventListener('load', function(e) {
2503
- if (req.status == 200) {
2504
- content = req.response;
2505
- }
2506
- });
2507
- req.addEventListener('loadend', function() {
2508
- if (content) {
2509
- mproj.internal.mproj_insert_libcache(libName, content);
2510
- }
2511
- // TODO: consider stopping with an error message if no content was loaded
2512
- // (currently, a less specific error will occur when mapshaper tries to use the library)
2513
- next();
2514
- });
2515
- req.open('GET', 'assets/' + libName);
2516
- req.send();
2517
- i++;
2489
+ libs = libs.filter(function(name) {return !mproj.internal.mproj_search_libcache(name);}); // skip loaded libs
2490
+ for (var libName of libs) {
2491
+ var content = await fetch('assets/' + libName).then(resp => resp.ok ? resp.text() : null);
2492
+ if (!content) stop$1(`Unable to load projection resource [${libName}]`);
2493
+ mproj.internal.mproj_insert_libcache(libName, content);
2518
2494
  }
2519
2495
  }
2520
2496
 
@@ -3371,7 +3347,10 @@
3371
3347
  setDisplayProjection(gui, cmd);
3372
3348
  } else {
3373
3349
  line.hide(); // hide cursor while command is being run
3374
- runMapshaperCommands(cmd, function(err) {
3350
+ runMapshaperCommands(cmd, function(err, flags) {
3351
+ if (flags) {
3352
+ gui.clearMode();
3353
+ }
3375
3354
  if (err) {
3376
3355
  onError(err);
3377
3356
  }
@@ -3404,14 +3383,9 @@
3404
3383
  }
3405
3384
  }
3406
3385
  if (flags) {
3407
- // if the command may have changed data, and a tool with an edit mode is being used,
3408
- // close the tool. (we may need a better way to allow the console and other tools
3409
- // to be used at the same time).
3410
- gui.clearMode();
3411
-
3412
3386
  model.updated(flags); // info commands do not return flags
3413
3387
  }
3414
- done(err);
3388
+ done(err, flags);
3415
3389
  });
3416
3390
  }
3417
3391
 
@@ -5068,7 +5042,8 @@
5068
5042
 
5069
5043
  // Handle an error caused by invalid input or misuse of API
5070
5044
  function stop() {
5071
- _stop.apply(null, utils.toArray(arguments));
5045
+ // _stop.apply(null, utils.toArray(arguments));
5046
+ _stop.apply(null, messageArgs(arguments));
5072
5047
  }
5073
5048
 
5074
5049
  function interrupt() {
@@ -7976,10 +7951,11 @@
7976
7951
  hit.clearSelection();
7977
7952
  });
7978
7953
 
7979
- function runCommand(cmd) {
7954
+ function runCommand(cmd, turnOff) {
7980
7955
  popup.hide();
7981
7956
  if (gui.console) gui.console.runMapshaperCommands(cmd, function(err) {
7982
7957
  reset();
7958
+ if (turnOff) gui.clearMode();
7983
7959
  });
7984
7960
  }
7985
7961
  }
@@ -10311,6 +10287,7 @@
10311
10287
  if (gui.console) {
10312
10288
  gui.console.runMapshaperCommands(cmd, function(err) {
10313
10289
  reset();
10290
+ gui.clearMode();
10314
10291
  });
10315
10292
  }
10316
10293
  // reset(); // TODO: exit interactive mode
package/www/mapshaper.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.6.38";
3
+ var VERSION = "0.6.39";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -65,7 +65,7 @@
65
65
  get rtrim () { return rtrim; },
66
66
  get addThousandsSep () { return addThousandsSep; },
67
67
  get numToStr () { return numToStr; },
68
- get formatNumber () { return formatNumber; },
68
+ get formatNumber () { return formatNumber$1; },
69
69
  get formatIntlNumber () { return formatIntlNumber; },
70
70
  get formatNumberForDisplay () { return formatNumberForDisplay; },
71
71
  get shuffle () { return shuffle; },
@@ -649,12 +649,12 @@
649
649
  return decimals >= 0 ? num.toFixed(decimals) : String(num);
650
650
  }
651
651
 
652
- function formatNumber(val) {
652
+ function formatNumber$1(val) {
653
653
  return val + '';
654
654
  }
655
655
 
656
656
  function formatIntlNumber(val) {
657
- var str = formatNumber(val);
657
+ var str = formatNumber$1(val);
658
658
  return '"' + str.replace('.', ',') + '"'; // need to quote if comma-delimited
659
659
  }
660
660
 
@@ -1247,7 +1247,8 @@
1247
1247
 
1248
1248
  // Handle an error caused by invalid input or misuse of API
1249
1249
  function stop() {
1250
- _stop.apply(null, utils.toArray(arguments));
1250
+ // _stop.apply(null, utils.toArray(arguments));
1251
+ _stop.apply(null, messageArgs(arguments));
1251
1252
  }
1252
1253
 
1253
1254
  function interrupt() {
@@ -4670,12 +4671,11 @@
4670
4671
  albersusa: AlbersUSA
4671
4672
  };
4672
4673
 
4673
- // This stub is replaced when loaded in GUI, which may need to load some files
4674
- function initProjLibrary(opts, done) {
4675
- if (!asyncLoader) return done();
4676
- asyncLoader(opts, done);
4674
+ async function initProjLibrary(opts) {
4675
+ if (asyncLoader) await asyncLoader(opts);
4677
4676
  }
4678
4677
 
4678
+ // used by web UI to support loading projection assets asyncronously
4679
4679
  function setProjectionLoader(loader) {
4680
4680
  asyncLoader = loader;
4681
4681
  }
@@ -13115,6 +13115,105 @@
13115
13115
  });
13116
13116
  }
13117
13117
 
13118
+ // Parse a formatted value in DMS DM or D to a numeric value. Returns NaN if unparsable.
13119
+ // Delimiters: degrees: D|d|°; minutes: '; seconds: "
13120
+ function parseDMS(str, fmt) {
13121
+ var defaultRxp = /^(?<prefix>[nsew+-]?)(?<d>[0-9.]+)[d°]? ?(?<m>[0-9.]*)['′]? ?(?<s>[0-9.]*)["″]? ?(?<suffix>[nsew]?)$/i;
13122
+ var rxp = fmt ? getParseRxp(fmt) : defaultRxp;
13123
+ var match = rxp.exec(str.trim());
13124
+ var d = NaN;
13125
+ var deg, min, sec;
13126
+ if (match) {
13127
+ deg = match.groups.d || '0';
13128
+ min = match.groups.m || '0';
13129
+ sec = match.groups.s || '0';
13130
+ d = (+deg) + (+min) / 60 + (+sec) / 3600;
13131
+ if (/[sw-]/i.test(match.groups.prefix || '') || /[sw]/i.test(match.groups.suffix || '')) {
13132
+ d = -d;
13133
+ }
13134
+ }
13135
+ return d;
13136
+ }
13137
+
13138
+ var cache$1 = {};
13139
+
13140
+ function getParseRxp(fmt) {
13141
+ if (fmt in cache$1) return cache$1[fmt];
13142
+ var rxp = fmt;
13143
+ rxp = rxp.replace('[-]', '(?<prefix>-)?'); // optional -
13144
+ rxp = rxp.replace(/\[[NSEW, +-]{2,}\]/, '(?<prefix>$&)');
13145
+ rxp = rxp.replace(/(MM?)(\.M+)?/, (m, g1, g2) => {
13146
+ var s = g1.length == 1 ? '[0-9]+' : '[0-9][0-9]';
13147
+ if (g2) s += `\\.[0-9]+`;
13148
+ return `(?<m>${s})`;
13149
+ });
13150
+ rxp = rxp.replace(/(SS?)(\.S+)?/, (m, g1, g2) => {
13151
+ var s = g1.length == 1 ? '[0-9]+' : '[0-9][0-9]';
13152
+ if (g2) s += `\\.[0-9]+`;
13153
+ return `(?<s>${s})`;
13154
+ });
13155
+ rxp = rxp.replace(/D+/, '(?<d>[0-9]+)');
13156
+ rxp = '^' + rxp + '$';
13157
+ try {
13158
+ // TODO: make sure all DMS codes have been matched
13159
+ cache$1[fmt] = new RegExp(rxp);
13160
+ } catch(e) {
13161
+ stop('Invalid DMS format string:', fmt);
13162
+ }
13163
+ return cache$1[fmt];
13164
+ }
13165
+
13166
+ function formatNumber(val, integers, decimals) {
13167
+ var str = val.toFixed(decimals);
13168
+ var parts = str.split('.');
13169
+ if (parts.length > 0) {
13170
+ parts[0] = parts[0].padStart(integers, '0');
13171
+ str = parts.join('.');
13172
+ }
13173
+ return str;
13174
+ }
13175
+
13176
+ function getDecimals(fmt) {
13177
+ var match = /S\.(S+)/.exec(fmt) || /M\.(M+)/.exec(fmt) || null;
13178
+ return match ? match[1].length : 0;
13179
+ }
13180
+
13181
+ // TODO: support DD.DDDDD
13182
+ function formatDMS(coord, fmt) {
13183
+ if (!fmt) fmt = '[-]D°M\'S.SSS';
13184
+ var str = fmt;
13185
+ var dstr, mstr, sstr;
13186
+ var match = /(D+)[^M]*(M+)[^S[\]]*(S+)?/.exec(fmt);
13187
+ if (!match) {
13188
+ stop('Invalid DMS format string:', fmt);
13189
+ }
13190
+ var gotSeconds = !!match[3];
13191
+ var decimals = getDecimals(fmt);
13192
+ var integers = gotSeconds ? match[3].length : match[2].length;
13193
+ var RES = Math.pow(10, decimals);
13194
+ var CONV = gotSeconds ? 3600 * RES : 60 * RES;
13195
+ var r = Math.floor(Math.abs(coord) * CONV + 0.5);
13196
+ var lastPart = formatNumber((r / RES) % 60, integers, decimals);
13197
+ if (gotSeconds) {
13198
+ r = Math.floor(r / (RES * 60));
13199
+ sstr = lastPart;
13200
+ mstr = String(r % 60).padStart(match[2].length, '0');
13201
+ } else {
13202
+ r = Math.floor(r / RES);
13203
+ mstr = lastPart;
13204
+ sstr = '';
13205
+ }
13206
+ dstr = String(Math.floor(r / 60)).padStart(match[1].length, '0');
13207
+ str = str.replace(/\[-\]/, s => coord < 0 ? '-' : '');
13208
+ str = str.replace(/\[[+-]+\]/, s => coord < 0 ? '-' : '+');
13209
+ str = str.replace(/\[[NS, ]+\]/, s => coord < 0 ? 'S' : 'N');
13210
+ str = str.replace(/\[[EW, ]+\]/, s => coord < 0 ? 'W' : 'E');
13211
+ str = str.replace(/D+/, dstr);
13212
+ str = str.replace(/M+(\.M+)?/, mstr);
13213
+ if (gotSeconds) str = str.replace(/S+(\.S+)?/, sstr);
13214
+ return str;
13215
+ }
13216
+
13118
13217
  function cleanExpression(exp) {
13119
13218
  // workaround for problem in GNU Make v4: end-of-line backslashes inside
13120
13219
  // quoted strings are left in the string (other shell environments remove them)
@@ -13126,7 +13225,9 @@
13126
13225
  round: roundToDigits2,
13127
13226
  int_median: interpolated_median,
13128
13227
  sprintf: utils.format,
13129
- blend: blend
13228
+ blend: blend,
13229
+ format_dms: formatDMS,
13230
+ parse_dms: parseDMS
13130
13231
  });
13131
13232
  }
13132
13233
 
@@ -22791,7 +22892,6 @@ ${svg}
22791
22892
 
22792
22893
  this.getHelpMessage = function(cmdName) {
22793
22894
  var helpCommands, singleCommand, lines;
22794
-
22795
22895
  if (cmdName) {
22796
22896
  singleCommand = findCommandDefn(cmdName, getCommands());
22797
22897
  if (!singleCommand) {
@@ -22910,10 +23010,6 @@ ${svg}
22910
23010
  }
22911
23011
  };
22912
23012
 
22913
- this.printHelp = function(command) {
22914
- print(this.getHelpMessage(command));
22915
- };
22916
-
22917
23013
  function getCommands() {
22918
23014
  return _commands.map(function(cmd) {
22919
23015
  return cmd.done();
@@ -23633,7 +23729,7 @@ ${svg}
23633
23729
  type: 'flag'
23634
23730
  })
23635
23731
  .option('other', {
23636
- describe: 'default color for categorical scheme (defaults to no-data color)'
23732
+ describe: 'default color for categorical scheme (default is nodata color)'
23637
23733
  })
23638
23734
  .option('nodata', {
23639
23735
  describe: 'color to use for invalid or missing data (default is white)'
@@ -24561,7 +24657,7 @@ ${svg}
24561
24657
  parser.command('symbols')
24562
24658
  .describe('symbolize points as arrows, circles, stars, polygons, etc.')
24563
24659
  .option('type', {
24564
- describe: 'symbol type (e.g. arrow, circle, square, star, polygon, ring)'
24660
+ describe: 'types: arrow, circle, square, star, polygon, ring'
24565
24661
  })
24566
24662
  .option('stroke', {})
24567
24663
  .option('stroke-width', {})
@@ -24575,8 +24671,7 @@ ${svg}
24575
24671
  describe: 'symbol line width (linear symbols only)'
24576
24672
  })
24577
24673
  .option('opacity', {
24578
- describe: 'symbol opacity',
24579
- type: 'number'
24674
+ describe: 'symbol opacity'
24580
24675
  })
24581
24676
  .option('geographic', {
24582
24677
  old_alias: 'polygons',
@@ -24678,7 +24773,6 @@ ${svg}
24678
24773
  .option('no-replace', noReplaceOpt);
24679
24774
  // .option('name', nameOpt);
24680
24775
 
24681
-
24682
24776
  parser.command('target')
24683
24777
  .describe('set active layer (or layers)')
24684
24778
  .option('target', {
@@ -24688,6 +24782,14 @@ ${svg}
24688
24782
  .option('type', {
24689
24783
  describe: 'type of layer to target (polygon|polyline|point)'
24690
24784
  })
24785
+ // .option('combine', {
24786
+ // type: 'flag',
24787
+ // describe: 'place all targeted layers in one dataset together with any associated layers'
24788
+ // })
24789
+ // .option('isolate', {
24790
+ // type: 'flag',
24791
+ // describe: 'place all targeted layers in one dataset exclusive of associated layers'
24792
+ // })
24691
24793
  .option('name', {
24692
24794
  describe: 'rename the target layer'
24693
24795
  });
@@ -38520,6 +38622,11 @@ ${svg}
38520
38622
  };
38521
38623
  }
38522
38624
 
38625
+ cmd.printHelp = function(opts) {
38626
+ var str = getOptionParser().getHelpMessage(opts.command);
38627
+ print(str);
38628
+ };
38629
+
38523
38630
  function resetControlFlow(job) {
38524
38631
  job.control = null;
38525
38632
  }
@@ -39159,25 +39266,6 @@ ${svg}
39159
39266
  };
39160
39267
  }
39161
39268
 
39162
- // Parse a formatted value in DMS DM or D to a numeric value. Returns NaN if unparsable.
39163
- // Delimiters: degrees: D|d|°; minutes: '; seconds: "
39164
- function parseDMS(str) {
39165
- var rxp = /^([nsew+-]?)([0-9.]+)[d°]? ?([0-9.]*)['′]? ?([0-9.]*)["″]? ?([nsew]?)$/i;
39166
- var match = rxp.exec(str.trim());
39167
- var d = NaN;
39168
- var deg, min, sec;
39169
- if (match) {
39170
- deg = match[2] || '0';
39171
- min = match[3] || '0';
39172
- sec = match[4] || '0';
39173
- d = (+deg) + (+min) / 60 + (+sec) / 3600;
39174
- if (/[sw-]/i.test(match[1]) || /[sw]/i.test(match[5])) {
39175
- d = -d;
39176
- }
39177
- }
39178
- return d;
39179
- }
39180
-
39181
39269
  function findNearestVertices(p, shp, arcs) {
39182
39270
  var p2 = findNearestVertex(p[0], p[1], shp, arcs);
39183
39271
  return findVertexIds(p2.x, p2.y, arcs);
@@ -42827,9 +42915,41 @@ ${svg}
42827
42915
  // TODO: improve this
42828
42916
  targets[0].layers[0].name = opts.name;
42829
42917
  }
42918
+ if (opts.combine) {
42919
+ targets = combineTargets(targets, catalog);
42920
+ } else if (opts.isolate) {
42921
+ targets = isolateTargets(targets, catalog);
42922
+ }
42830
42923
  catalog.setDefaultTargets(targets);
42831
42924
  };
42832
42925
 
42926
+ function combineTargets(targets, catalog) {
42927
+ var datasets = [];
42928
+ var layers = [];
42929
+ targets.forEach(function(o) {
42930
+ datasets.push(o.dataset);
42931
+ catalog.removeDataset(o.dataset);
42932
+ layers = layers.concat(o.layers);
42933
+ });
42934
+ var combined = mergeDatasets(datasets);
42935
+ catalog.addDataset(combined);
42936
+ return [{
42937
+ dataset: combined,
42938
+ layers: layers
42939
+ }];
42940
+ }
42941
+
42942
+ function isolateTargets(targets, catalog) {
42943
+ var datasets = [];
42944
+ targets.forEach(function(o) {
42945
+ datasets.push(o.dataset);
42946
+ o.layers.forEach(function(lyr) {
42947
+ catalog.removeLayer(lyr, o.dataset);
42948
+
42949
+ });
42950
+ });
42951
+ }
42952
+
42833
42953
  cmd.union = function(targetLayers, targetDataset, opts) {
42834
42954
  if (targetLayers.length < 2) {
42835
42955
  stop('Command requires at least two target layers');
@@ -43214,7 +43334,7 @@ ${svg}
43214
43334
  function commandAcceptsMultipleTargetDatasets(name) {
43215
43335
  return name == 'rotate' || name == 'info' || name == 'proj' ||
43216
43336
  name == 'drop' || name == 'target' || name == 'if' || name == 'elif' ||
43217
- name == 'else' || name == 'endif' || name == 'run';
43337
+ name == 'else' || name == 'endif' || name == 'run' || name == 'i';
43218
43338
  }
43219
43339
 
43220
43340
  function commandAcceptsEmptyTarget(name) {
@@ -43403,8 +43523,8 @@ ${svg}
43403
43523
  job.catalog.addDataset(cmd.graticule(targetDataset, opts));
43404
43524
 
43405
43525
  } else if (name == 'help') {
43406
- // placing this here to handle errors from invalid command names
43407
- getOptionParser().printHelp(command.options.command);
43526
+ // placing help command here to handle errors from invalid command names
43527
+ cmd.printHelp(command.options);
43408
43528
 
43409
43529
  } else if (name == 'i') {
43410
43530
  if (opts.replace) job.catalog = new Catalog(); // is this what we want?
@@ -43486,7 +43606,7 @@ ${svg}
43486
43606
  cmd.print(command._.join(' '));
43487
43607
 
43488
43608
  } else if (name == 'proj') {
43489
- await utils.promisify(initProjLibrary)(opts);
43609
+ await initProjLibrary(opts);
43490
43610
  job.resumeCommand();
43491
43611
  targets.forEach(function(targ) {
43492
43612
  cmd.proj(targ.dataset, job.catalog, opts);
@@ -44321,6 +44441,7 @@ ${svg}
44321
44441
  Heap,
44322
44442
  NodeCollection,
44323
44443
  parseDMS,
44444
+ formatDMS,
44324
44445
  PathIndex,
44325
44446
  PolygonIndex,
44326
44447
  ShpReader,