mapshaper 0.7.10 → 0.7.12

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
@@ -17021,7 +17021,8 @@
17021
17021
  var groups = groupPolygonRings(obj.pathData, arcs, opts.invert_y);
17022
17022
  // invert_y is used internally for SVG generation
17023
17023
  // mapshaper's internal winding order is the opposite of RFC 7946
17024
- var reverse = opts.rfc7946 && !opts.invert_y;
17024
+ var rfc7946 = opts.rfc7946 === true;
17025
+ var reverse = rfc7946 !== !!opts.reverse_winding && !opts.invert_y;
17025
17026
  var coords = groups.map(function(paths) {
17026
17027
  return paths.map(function(path) {
17027
17028
  if (reverse) path.points.reverse();
@@ -26408,37 +26409,25 @@ ${svg}
26408
26409
  async function loadZstdLib() {
26409
26410
  var mod;
26410
26411
  if (runningInBrowser()) {
26411
- mod = require$1('zstd-codec');
26412
+ mod = require$1('@bokuweb/zstd-wasm');
26412
26413
  } else {
26413
26414
  if (!zstdPromise) {
26414
- zstdPromise = dynamicImportModule$1('zstd-codec');
26415
+ zstdPromise = dynamicImportModule$1('@bokuweb/zstd-wasm');
26415
26416
  }
26416
26417
  mod = await zstdPromise;
26417
26418
  }
26418
- if (mod && mod.default && !mod.ZstdCodec) {
26419
+ if (mod && mod.default && !mod.compress) {
26419
26420
  mod = mod.default;
26420
26421
  }
26421
- if (!mod || !mod.ZstdCodec || typeof mod.ZstdCodec.run != 'function') {
26422
+ if (!mod || typeof mod.init != 'function' || typeof mod.compress != 'function') {
26422
26423
  stop$1('GeoParquet ZSTD compressor is not loaded');
26423
26424
  }
26424
- return initZstdCodec(mod.ZstdCodec);
26425
+ await mod.init();
26426
+ return initZstdCodec(mod);
26425
26427
  }
26426
26428
 
26427
26429
  function initZstdCodec(codec) {
26428
- return new Promise(function(resolve, reject) {
26429
- try {
26430
- codec.run(function(zstd) {
26431
- var simple = new zstd.Simple();
26432
- resolve({
26433
- compress: function(bytes, level) {
26434
- return simple.compress(bytes, level);
26435
- }
26436
- });
26437
- });
26438
- } catch (e) {
26439
- reject(e);
26440
- }
26441
- });
26430
+ return codec;
26442
26431
  }
26443
26432
 
26444
26433
  function getOutputFormat(dataset, opts) {
@@ -29145,6 +29134,10 @@ ${svg}
29145
29134
  describe: '[GeoJSON] use original GeoJSON spec (not RFC 7946)',
29146
29135
  type: 'flag'
29147
29136
  })
29137
+ .option('reverse-winding', {
29138
+ describe: '[GeoJSON] reverse polygon winding order',
29139
+ type: 'flag'
29140
+ })
29148
29141
  .option('rfc7946', {
29149
29142
  // dummy option so old commands do not break
29150
29143
  type: 'flag'
@@ -34623,8 +34616,8 @@ ${svg}
34623
34616
  var candidates = getGeoParquetCrsStrings(crs);
34624
34617
  for (var i = 0; i < candidates.length; i++) {
34625
34618
  try {
34626
- parseCrsString$1(candidates[i]);
34627
34619
  await initProjLibrary({crs: candidates[i]});
34620
+ parseCrsString$1(candidates[i]);
34628
34621
  return candidates[i];
34629
34622
  } catch (e) {
34630
34623
  // Keep trying candidates; if none initialize, caller will warn.
@@ -48771,7 +48764,7 @@ ${svg}
48771
48764
  return layerHasGeometry(lyr) && !layerIsFullyEnclosed(lyr, dataset, clipData);
48772
48765
  });
48773
48766
  if (layers.length > 0) {
48774
- clipLayersInPlace(layers, clipData, dataset, 'clip');
48767
+ clipLayersInPlace(layers, clipData, dataset, 'clip', getInternalClipOpts());
48775
48768
  return true;
48776
48769
  }
48777
48770
  return false;
@@ -48810,13 +48803,21 @@ ${svg}
48810
48803
  }
48811
48804
 
48812
48805
  function datasetCrossesLon(dataset, lon) {
48813
- var crosses = 0;
48814
- dataset.arcs.forEachSegment(function(i, j, xx, yy) {
48815
- var ax = xx[i],
48816
- bx = xx[j];
48817
- if (ax <= lon && bx >= lon || ax >= lon && bx <= lon) crosses++;
48806
+ var crosses = false;
48807
+ dataset.layers.filter(layerHasPaths).forEach(function(lyr) {
48808
+ if (crosses) return;
48809
+ lyr.shapes.forEach(function(shp) {
48810
+ if (crosses || !shp) return;
48811
+ forEachSegmentInShape(shp, dataset.arcs, function(i, j, xx, yy) {
48812
+ var ax = xx[i],
48813
+ bx = xx[j];
48814
+ if (ax <= lon && bx >= lon || ax >= lon && bx <= lon) {
48815
+ crosses = true;
48816
+ }
48817
+ });
48818
+ });
48818
48819
  });
48819
- return crosses > 0;
48820
+ return crosses;
48820
48821
  }
48821
48822
 
48822
48823
  function insertVerticalCut(dataset, lon) {
@@ -48827,29 +48828,38 @@ ${svg}
48827
48828
  // densify (so cut line can curve, e.g. Cupola projection)
48828
48829
  var geojson = bboxToPolygon(bbox, {interval: 0.5});
48829
48830
  var clip = importGeoJSON(geojson);
48830
- clipLayersInPlace(pathLayers, clip, dataset, 'erase');
48831
+ clipLayersInPlace(pathLayers, clip, dataset, 'erase', getInternalClipOpts());
48832
+ }
48833
+
48834
+ function getInternalClipOpts() {
48835
+ return {no_cleanup: true, no_warn: true};
48831
48836
  }
48832
48837
 
48833
- // Converts a Proj.4 projection name (e.g. lcc, tmerc) to a Proj.4 string
48838
+ // Converts a Proj.4 projection name (e.g. lcc, tmerc, utm) to a Proj.4 string
48834
48839
  // by picking parameters that are appropriate to the extent of the dataset
48835
48840
  // being projected (e.g. standard parallels, longitude of origin)
48836
- // Works for lcc, aea, tmerc, etc.
48841
+ // Works for lcc, aea, tmerc, utm, etc.
48837
48842
  // TODO: add more projections
48838
48843
  //
48839
48844
  function expandProjDefn(str, dataset, targetLayers) {
48840
48845
  var mproj = require$1('mproj');
48841
- var proj4, params, bbox, isConic2SP, isCentered, decimals;
48846
+ var proj4, params, bbox, isConic2SP, isCentered, isUtm, decimals;
48842
48847
  if (str in mproj.internal.pj_list === false) {
48843
48848
  // not a bare projection code -- assume valid projection string in other format
48844
48849
  return str;
48845
48850
  }
48846
48851
  isConic2SP = ['lcc', 'aea'].includes(str);
48847
48852
  isCentered = ['tmerc', 'etmerc'].includes(str);
48853
+ isUtm = str == 'utm';
48848
48854
  proj4 = '+proj=' + str;
48849
- if (isConic2SP || isCentered) {
48855
+ if (isConic2SP || isCentered || isUtm) {
48850
48856
  bbox = getBBox(dataset, targetLayers); // TODO: support projected datasets
48851
48857
  decimals = getBoundsPrecisionForDisplay(bbox);
48852
- params = isCentered ? getCenterParams(bbox, decimals) : getConicParams(bbox, decimals);
48858
+ if (isUtm) {
48859
+ params = getUtmParams(bbox);
48860
+ } else {
48861
+ params = isCentered ? getCenterParams(bbox, decimals) : getConicParams(bbox, decimals);
48862
+ }
48853
48863
  proj4 += ' ' + params;
48854
48864
  message(`Converted "${str}" to "${proj4}"`);
48855
48865
  }
@@ -48865,7 +48875,77 @@ ${svg}
48865
48875
  if (!isLatLngCRS(getDatasetCRS(dataset))) {
48866
48876
  stop$1('Expected unprojected data');
48867
48877
  }
48868
- return getDatasetBounds(source).toArray();
48878
+ return getAutoFitBBox(source);
48879
+ }
48880
+
48881
+ function getAutoFitBBox(dataset) {
48882
+ var bbox = getDatasetBounds(dataset).toArray();
48883
+ if (bbox[2] - bbox[0] > 180) {
48884
+ bbox = getWrappedBBox(dataset, bbox) || bbox;
48885
+ }
48886
+ return bbox;
48887
+ }
48888
+
48889
+ function getWrappedBBox(dataset, bbox) {
48890
+ var xmaxW = -Infinity,
48891
+ xminE = Infinity, xmaxE = -Infinity,
48892
+ ymin = bbox[1], ymax = bbox[3],
48893
+ gap;
48894
+
48895
+ // Detect dateline clustering with a streaming east/west split. The gap
48896
+ // between the two boxes can only shrink as more coordinates are scanned.
48897
+ forEachDatasetCoord(dataset, function(x) {
48898
+ if (x < 0) {
48899
+ if (x > xmaxW) xmaxW = x;
48900
+ } else {
48901
+ if (x < xminE) xminE = x;
48902
+ if (x > xmaxE) xmaxE = x;
48903
+ }
48904
+ if (xmaxW > -Infinity && xmaxE > -Infinity) {
48905
+ gap = xminE - xmaxW;
48906
+ return gap > 180;
48907
+ }
48908
+ });
48909
+
48910
+ if (xmaxW == -Infinity || xmaxE == -Infinity) return null;
48911
+ if (xminE - xmaxW <= 180) return null;
48912
+ return [xminE, ymin, xmaxW + 360, ymax];
48913
+ }
48914
+
48915
+ function forEachDatasetCoord(dataset, cb) {
48916
+ var arcs = dataset.arcs;
48917
+ var usedArcs = arcs ? new Uint8Array(arcs.size()) : null;
48918
+ var keepGoing = true;
48919
+ dataset.layers.forEach(function(lyr) {
48920
+ if (!keepGoing) return;
48921
+ if (lyr.geometry_type == 'point') {
48922
+ keepGoing = scanPointCoords(lyr.shapes, cb);
48923
+ } else if (arcs && (lyr.geometry_type == 'polygon' || lyr.geometry_type == 'polyline')) {
48924
+ forEachArcId(lyr.shapes, function(id) {
48925
+ var absId, iter;
48926
+ if (!keepGoing) return;
48927
+ absId = id < 0 ? ~id : id;
48928
+ if (usedArcs[absId]) return;
48929
+ usedArcs[absId] = 1;
48930
+ iter = arcs.getArcIter(absId);
48931
+ while (keepGoing && iter.hasNext()) {
48932
+ keepGoing = cb(iter.x, iter.y) !== false;
48933
+ }
48934
+ });
48935
+ }
48936
+ });
48937
+ }
48938
+
48939
+ function scanPointCoords(shapes, cb) {
48940
+ var shp, p;
48941
+ for (var i=0, n=shapes.length; i<n; i++) {
48942
+ shp = shapes[i];
48943
+ for (var j=0, m=shp ? shp.length : 0; j<m; j++) {
48944
+ p = shp[j];
48945
+ if (cb(p[0], p[1]) === false) return false;
48946
+ }
48947
+ }
48948
+ return true;
48869
48949
  }
48870
48950
 
48871
48951
  // See: Savric & Jenny, "Automating the selection of standard parallels for conic map projections"
@@ -48884,11 +48964,21 @@ ${svg}
48884
48964
  return `+lon_0=${ cx.toFixed(decimals) } +lat_0=${ cy.toFixed(decimals) }`;
48885
48965
  }
48886
48966
 
48967
+ function getUtmParams(bbox) {
48968
+ var cx = (bbox[0] + bbox[2]) / 2;
48969
+ var cy = (bbox[1] + bbox[3]) / 2;
48970
+ var zone = Math.floor((cx + 180) / 6) + 1;
48971
+ zone = Math.max(1, Math.min(60, zone));
48972
+ return `+zone=${ zone }` + (cy < 0 ? ' +south' : '');
48973
+ }
48974
+
48887
48975
  var ProjectionParams = /*#__PURE__*/Object.freeze({
48888
48976
  __proto__: null,
48889
48977
  expandProjDefn: expandProjDefn,
48978
+ getAutoFitBBox: getAutoFitBBox,
48890
48979
  getCenterParams: getCenterParams,
48891
- getConicParams: getConicParams
48980
+ getConicParams: getConicParams,
48981
+ getUtmParams: getUtmParams
48892
48982
  });
48893
48983
 
48894
48984
  cmd.proj = function(dataset, catalog, opts, targetLayers) {
@@ -55438,7 +55528,7 @@ ${svg}
55438
55528
  });
55439
55529
  }
55440
55530
 
55441
- var version = "0.7.10";
55531
+ var version = "0.7.12";
55442
55532
 
55443
55533
  // Parse command line args into commands and run them
55444
55534
  // Function takes an optional Node-style callback. A Promise is returned if no callback is given.
@@ -55496,8 +55586,10 @@ ${svg}
55496
55586
  var child = require$1('child_process').exec(command, {}, function(err, stdout, stderr) {
55497
55587
  opts.callback(err);
55498
55588
  });
55499
- child.stdout.pipe(process.stdout);
55500
- child.stderr.pipe(process.stderr);
55589
+ if (loggingEnabled()) {
55590
+ child.stdout.pipe(process.stdout);
55591
+ child.stderr.pipe(process.stderr);
55592
+ }
55501
55593
  if (opts.promise) return opts.promise;
55502
55594
  }
55503
55595
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mapshaper",
3
- "version": "0.7.10",
3
+ "version": "0.7.12",
4
4
  "description": "A tool for editing vector datasets for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
@@ -23,15 +23,15 @@
23
23
  "node": ">=20.11.0"
24
24
  },
25
25
  "scripts": {
26
- "test": "mocha test",
26
+ "test": "mocha --require test/mocha-hooks.mjs test",
27
27
  "build": "rollup --config",
28
28
  "docs": "node build-docs.mjs",
29
29
  "roadmap": "node build-roadmap.mjs",
30
30
  "lint": "eslint --ext mjs src/",
31
- "prepublishOnly": "npm test; ./pre-publish",
31
+ "prepublishOnly": "npm test && npm run test:browser && ./pre-publish",
32
32
  "postpublish": "./release_web_ui; ./release_github_version",
33
33
  "dev": "rollup --config --watch",
34
- "test:browser": "playwright test"
34
+ "test:browser": "playwright test --fully-parallel --workers=6"
35
35
  },
36
36
  "main": "./mapshaper.js",
37
37
  "files": [
@@ -45,6 +45,7 @@
45
45
  "!/www/ai-config.js"
46
46
  ],
47
47
  "dependencies": {
48
+ "@bokuweb/zstd-wasm": "^0.0.27",
48
49
  "@ngageoint/geopackage": "^4.2.6",
49
50
  "@placemarkio/tokml": "^0.3.3",
50
51
  "@tmcw/togeojson": "^5.6.0",
@@ -72,8 +73,7 @@
72
73
  "msgpackr": "^1.10.1",
73
74
  "open": "^11.0.0",
74
75
  "rw": "~1.3.3",
75
- "tinyqueue": "^2.0.3",
76
- "zstd-codec": "^0.1.5"
76
+ "tinyqueue": "^2.0.3"
77
77
  },
78
78
  "devDependencies": {
79
79
  "@playwright/test": "^1.59.1",