mapshaper 0.6.32 → 0.6.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/mapshaper.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.6.32";
3
+ var VERSION = "0.6.33";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -11665,8 +11665,16 @@
11665
11665
  }
11666
11666
  cands.forEach(function(cand) {
11667
11667
  var p = getTestPoint(cand.ids);
11668
- var isEnclosed = b.containsPoint(p[0], p[1]) && (index ?
11669
- index.pointInPolygon(p[0], p[1]) : geom.testPointInRing(p[0], p[1], pathIds, arcs));
11668
+ var isEnclosed = b.containsPoint(p[0], p[1]) &&
11669
+ // added a bounds-in-bounds test to handle a case where the test point
11670
+ // fell along the shared boundary of two rings, but the rings did no overlap
11671
+ // (this gave a false positive for the enclosure test)
11672
+ // (for speed, the midpoint of an arc is used as the test point; this
11673
+ // works well in the typical case where rings to not share an edge.
11674
+ // Finding an internal test point would be better, we just need a fast
11675
+ // function to find internal points)
11676
+ b.contains(cand.bounds) &&
11677
+ (index ? index.pointInPolygon(p[0], p[1]) : geom.testPointInRing(p[0], p[1], pathIds, arcs));
11670
11678
  if (isEnclosed) {
11671
11679
  paths.push(cand.ids);
11672
11680
  }
@@ -11674,6 +11682,7 @@
11674
11682
  return paths.length > 0 ? paths : null;
11675
11683
  };
11676
11684
 
11685
+ // return array of indexed paths within a given shape
11677
11686
  this.findPathsInsideShape = function(shape) {
11678
11687
  var paths = []; // list of enclosed paths
11679
11688
  shape.forEach(function(ids) {
@@ -12075,7 +12084,6 @@
12075
12084
  yy = coords.yy,
12076
12085
  ids = nodes.getConnectedArcs(fromArcId),
12077
12086
  toArcId = fromArcId; // initialize to fromArcId -- an error condition
12078
-
12079
12087
  if (filter) {
12080
12088
  ids = ids.filter(filter);
12081
12089
  }
@@ -12104,14 +12112,12 @@
12104
12112
  continue;
12105
12113
  }
12106
12114
  icand = arcs.indexOfVertex(candId, -2);
12107
-
12108
12115
  if (toArcId == fromArcId) {
12109
12116
  // first valid candidate
12110
12117
  ito = icand;
12111
12118
  toArcId = candId;
12112
12119
  continue;
12113
12120
  }
12114
-
12115
12121
  code = chooseRighthandPath(fromX, fromY, nodeX, nodeY, xx[ito], yy[ito], xx[icand], yy[icand]);
12116
12122
  if (code == 2) {
12117
12123
  ito = icand;
@@ -12119,6 +12125,7 @@
12119
12125
  }
12120
12126
  }
12121
12127
 
12128
+
12122
12129
  if (toArcId == fromArcId) {
12123
12130
  // This shouldn't occur, assuming that other arcs are present
12124
12131
  error("Pathfinder error");
@@ -12183,6 +12190,9 @@
12183
12190
  chooseRighthandVector: chooseRighthandVector
12184
12191
  });
12185
12192
 
12193
+ var FWD_USED = 0x8;
12194
+ var REV_USED = 0x80;
12195
+
12186
12196
  function setBits(bits, arcBits, mask) {
12187
12197
  return (bits & ~mask) | (arcBits & mask);
12188
12198
  }
@@ -12210,6 +12220,16 @@
12210
12220
  return bits & 7;
12211
12221
  }
12212
12222
 
12223
+ function markPathsAsUsed(paths, routesArr) {
12224
+ forEachArcId(paths, function(arcId) {
12225
+ if (arcId < 0) {
12226
+ routesArr[~arcId] |= REV_USED;
12227
+ } else {
12228
+ routesArr[arcId] |= FWD_USED;
12229
+ }
12230
+ });
12231
+ }
12232
+
12213
12233
  // Open arc pathways in a single shape or array of shapes
12214
12234
  //
12215
12235
  function openArcRoutes(paths, arcColl, routesArr, fwd, rev, dissolve, orBits) {
@@ -12400,6 +12420,7 @@
12400
12420
  andBits: andBits,
12401
12421
  setRouteBits: setRouteBits,
12402
12422
  getRouteBits: getRouteBits,
12423
+ markPathsAsUsed: markPathsAsUsed,
12403
12424
  openArcRoutes: openArcRoutes,
12404
12425
  closeArcRoutes: closeArcRoutes,
12405
12426
  getPathFinder: getPathFinder,
@@ -33401,7 +33422,7 @@ ${svg}
33401
33422
  var clipArcTouches = 0;
33402
33423
  var clipArcUses = 0;
33403
33424
  var usedClipArcs = [];
33404
- var dividePath = getPathFinder(nodes, useRoute, routeIsActive);
33425
+ var findPath = getPathFinder(nodes, useRoute, routeIsActive);
33405
33426
  var dissolvePolygon = getPolygonDissolver(nodes);
33406
33427
 
33407
33428
  // The following cleanup step is a performance bottleneck (it often takes longer than
@@ -33434,12 +33455,16 @@ ${svg}
33434
33455
  return null;
33435
33456
  });
33436
33457
 
33458
+ markPathsAsUsed(clippedShapes, routeFlags); // to help us find unused paths later
33459
+
33460
+
33437
33461
  // add clip/erase polygons that are fully contained in a target polygon
33438
33462
  // need to index only non-intersecting clip shapes
33439
33463
  // (Intersecting shapes have one or more arcs that have been scanned)
33440
33464
 
33441
33465
  // first, find shapes that do not intersect the target layer
33442
33466
  // (these could be inside or outside the target polygons)
33467
+
33443
33468
  var undividedClipShapes = findUndividedClipShapes(clipShapes);
33444
33469
 
33445
33470
  closeArcRoutes(clipShapes, arcs, routeFlags, true, true); // not needed?
@@ -33468,7 +33493,7 @@ ${svg}
33468
33493
  for (var i=0, n=ids.length; i<n; i++) {
33469
33494
  clipArcTouches = 0;
33470
33495
  clipArcUses = 0;
33471
- path = dividePath(ids[i]);
33496
+ path = findPath(ids[i]);
33472
33497
  if (path) {
33473
33498
  // if ring doesn't touch/intersect a clip/erase polygon, check if it is contained
33474
33499
  // if (clipArcTouches === 0) {
@@ -33487,6 +33512,7 @@ ${svg}
33487
33512
  }
33488
33513
  });
33489
33514
 
33515
+
33490
33516
  // Clear pathways of current target shape to hidden/closed
33491
33517
  closeArcRoutes(shape, arcs, routeFlags, true, true, true);
33492
33518
  // Also clear pathways of any clip arcs that were used
@@ -33557,8 +33583,9 @@ ${svg}
33557
33583
  return usable;
33558
33584
  }
33559
33585
 
33560
- // Filter a collection of shapes to exclude paths that contain clip/erase arcs
33561
- // and paths that are hidden (e.g. internal boundaries)
33586
+
33587
+ // Filter a collection of shapes to exclude paths that incorporate parts of
33588
+ // clip/erase polygons and paths that are hidden (e.g. internal boundaries)
33562
33589
  function findUndividedClipShapes(clipShapes) {
33563
33590
  return clipShapes.map(function(shape) {
33564
33591
  var usableParts = [];
@@ -33582,12 +33609,12 @@ ${svg}
33582
33609
  });
33583
33610
  }
33584
33611
 
33585
- // Test if arc is unused in both directions
33586
- // (not testing open/closed or visible/hidden)
33612
+
33587
33613
  function arcIsUnused(id, flags) {
33588
33614
  var abs = absArcId(id),
33589
33615
  flag = flags[abs];
33590
- return (flag & 0x44) === 0;
33616
+ return (flag & 0x88) === 0;
33617
+ // return id < 0 ? (flag & 0x80) === 0 : (flag & 0x8) === 0;
33591
33618
  }
33592
33619
 
33593
33620
  function arcIsVisible(id, flags) {
@@ -33610,7 +33637,7 @@ ${svg}
33610
33637
  enclosedPaths.forEach(function(ids) {
33611
33638
  var path;
33612
33639
  for (var j=0; j<ids.length; j++) {
33613
- path = dividePath(ids[j]);
33640
+ path = findPath(ids[j]);
33614
33641
  if (path) {
33615
33642
  dissolvedPaths.push(path);
33616
33643
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mapshaper",
3
- "version": "0.6.32",
3
+ "version": "0.6.33",
4
4
  "description": "A tool for editing vector datasets for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
@@ -4038,8 +4038,11 @@
4038
4038
  }
4039
4039
 
4040
4040
  function updateMenuBtn() {
4041
- var name = model.getActiveLayer().layer.name || "[unnamed layer]";
4042
- btn.classed('active', 'true').findChild('.layer-name').html(name + " &nbsp;&#9660;");
4041
+ var lyrName = model.getActiveLayer().layer.name || '';
4042
+ var menuTitle = lyrName || '[unnamed layer]';
4043
+ var pageTitle = lyrName || 'mapshaper';
4044
+ btn.classed('active', 'true').findChild('.layer-name').html(menuTitle + " &nbsp;&#9660;");
4045
+ window.document.title = pageTitle;
4043
4046
  }
4044
4047
 
4045
4048
  function render() {
@@ -10172,12 +10175,12 @@
10172
10175
  return action == 'hover' && _overlayCanv.visible();
10173
10176
  }
10174
10177
 
10175
- function drawCanvasLayer(target, canv) {
10176
- if (!target) return;
10177
- if (target.style.type == 'outline') {
10178
- drawOutlineLayerToCanvas(target, canv, ext);
10178
+ function drawCanvasLayer(lyr, canv) {
10179
+ if (!lyr) return;
10180
+ if (lyr.style.type == 'outline') {
10181
+ drawOutlineLayerToCanvas(lyr, canv, ext);
10179
10182
  } else {
10180
- drawStyledLayerToCanvas(target, canv, ext);
10183
+ drawStyledLayerToCanvas(lyr, canv, ext);
10181
10184
  }
10182
10185
  }
10183
10186
 
@@ -11039,7 +11042,9 @@
11039
11042
  } else {
11040
11043
  _overlayLyr = null;
11041
11044
  }
11042
- drawLayers('hover');
11045
+ // 'hover' bypasses style creation in drawLayers2()... sometimes we need that
11046
+ // drawLayers('hover');
11047
+ drawLayers();
11043
11048
  }
11044
11049
 
11045
11050
  function getDisplayOptions() {
@@ -11054,12 +11059,14 @@
11054
11059
  return flags.simplify_method || flags.simplify || flags.proj ||
11055
11060
  flags.arc_count || flags.repair || flags.clip || flags.erase ||
11056
11061
  flags.slice || flags.affine || flags.rectangle || flags.buffer ||
11057
- flags.union || flags.mosaic || flags.snap || flags.clean || false;
11062
+ flags.union || flags.mosaic || flags.snap || flags.clean || flags.drop || false;
11058
11063
  }
11059
11064
 
11060
11065
  // Test if an update allows hover popup to stay open
11061
11066
  function popupCanStayOpen(flags) {
11062
- // if (arcsMayHaveChanged(flags)) return false;
11067
+ // keeping popup open after -drop geometry causes problems...
11068
+ // // if (arcsMayHaveChanged(flags)) return false;
11069
+ if (arcsMayHaveChanged(flags)) return false;
11063
11070
  if (flags.points || flags.proj) return false;
11064
11071
  if (!flags.same_table) return false;
11065
11072
  return true;
package/www/mapshaper.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.6.32";
3
+ var VERSION = "0.6.33";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -11665,8 +11665,16 @@
11665
11665
  }
11666
11666
  cands.forEach(function(cand) {
11667
11667
  var p = getTestPoint(cand.ids);
11668
- var isEnclosed = b.containsPoint(p[0], p[1]) && (index ?
11669
- index.pointInPolygon(p[0], p[1]) : geom.testPointInRing(p[0], p[1], pathIds, arcs));
11668
+ var isEnclosed = b.containsPoint(p[0], p[1]) &&
11669
+ // added a bounds-in-bounds test to handle a case where the test point
11670
+ // fell along the shared boundary of two rings, but the rings did no overlap
11671
+ // (this gave a false positive for the enclosure test)
11672
+ // (for speed, the midpoint of an arc is used as the test point; this
11673
+ // works well in the typical case where rings to not share an edge.
11674
+ // Finding an internal test point would be better, we just need a fast
11675
+ // function to find internal points)
11676
+ b.contains(cand.bounds) &&
11677
+ (index ? index.pointInPolygon(p[0], p[1]) : geom.testPointInRing(p[0], p[1], pathIds, arcs));
11670
11678
  if (isEnclosed) {
11671
11679
  paths.push(cand.ids);
11672
11680
  }
@@ -11674,6 +11682,7 @@
11674
11682
  return paths.length > 0 ? paths : null;
11675
11683
  };
11676
11684
 
11685
+ // return array of indexed paths within a given shape
11677
11686
  this.findPathsInsideShape = function(shape) {
11678
11687
  var paths = []; // list of enclosed paths
11679
11688
  shape.forEach(function(ids) {
@@ -12075,7 +12084,6 @@
12075
12084
  yy = coords.yy,
12076
12085
  ids = nodes.getConnectedArcs(fromArcId),
12077
12086
  toArcId = fromArcId; // initialize to fromArcId -- an error condition
12078
-
12079
12087
  if (filter) {
12080
12088
  ids = ids.filter(filter);
12081
12089
  }
@@ -12104,14 +12112,12 @@
12104
12112
  continue;
12105
12113
  }
12106
12114
  icand = arcs.indexOfVertex(candId, -2);
12107
-
12108
12115
  if (toArcId == fromArcId) {
12109
12116
  // first valid candidate
12110
12117
  ito = icand;
12111
12118
  toArcId = candId;
12112
12119
  continue;
12113
12120
  }
12114
-
12115
12121
  code = chooseRighthandPath(fromX, fromY, nodeX, nodeY, xx[ito], yy[ito], xx[icand], yy[icand]);
12116
12122
  if (code == 2) {
12117
12123
  ito = icand;
@@ -12119,6 +12125,7 @@
12119
12125
  }
12120
12126
  }
12121
12127
 
12128
+
12122
12129
  if (toArcId == fromArcId) {
12123
12130
  // This shouldn't occur, assuming that other arcs are present
12124
12131
  error("Pathfinder error");
@@ -12183,6 +12190,9 @@
12183
12190
  chooseRighthandVector: chooseRighthandVector
12184
12191
  });
12185
12192
 
12193
+ var FWD_USED = 0x8;
12194
+ var REV_USED = 0x80;
12195
+
12186
12196
  function setBits(bits, arcBits, mask) {
12187
12197
  return (bits & ~mask) | (arcBits & mask);
12188
12198
  }
@@ -12210,6 +12220,16 @@
12210
12220
  return bits & 7;
12211
12221
  }
12212
12222
 
12223
+ function markPathsAsUsed(paths, routesArr) {
12224
+ forEachArcId(paths, function(arcId) {
12225
+ if (arcId < 0) {
12226
+ routesArr[~arcId] |= REV_USED;
12227
+ } else {
12228
+ routesArr[arcId] |= FWD_USED;
12229
+ }
12230
+ });
12231
+ }
12232
+
12213
12233
  // Open arc pathways in a single shape or array of shapes
12214
12234
  //
12215
12235
  function openArcRoutes(paths, arcColl, routesArr, fwd, rev, dissolve, orBits) {
@@ -12400,6 +12420,7 @@
12400
12420
  andBits: andBits,
12401
12421
  setRouteBits: setRouteBits,
12402
12422
  getRouteBits: getRouteBits,
12423
+ markPathsAsUsed: markPathsAsUsed,
12403
12424
  openArcRoutes: openArcRoutes,
12404
12425
  closeArcRoutes: closeArcRoutes,
12405
12426
  getPathFinder: getPathFinder,
@@ -33401,7 +33422,7 @@ ${svg}
33401
33422
  var clipArcTouches = 0;
33402
33423
  var clipArcUses = 0;
33403
33424
  var usedClipArcs = [];
33404
- var dividePath = getPathFinder(nodes, useRoute, routeIsActive);
33425
+ var findPath = getPathFinder(nodes, useRoute, routeIsActive);
33405
33426
  var dissolvePolygon = getPolygonDissolver(nodes);
33406
33427
 
33407
33428
  // The following cleanup step is a performance bottleneck (it often takes longer than
@@ -33434,12 +33455,16 @@ ${svg}
33434
33455
  return null;
33435
33456
  });
33436
33457
 
33458
+ markPathsAsUsed(clippedShapes, routeFlags); // to help us find unused paths later
33459
+
33460
+
33437
33461
  // add clip/erase polygons that are fully contained in a target polygon
33438
33462
  // need to index only non-intersecting clip shapes
33439
33463
  // (Intersecting shapes have one or more arcs that have been scanned)
33440
33464
 
33441
33465
  // first, find shapes that do not intersect the target layer
33442
33466
  // (these could be inside or outside the target polygons)
33467
+
33443
33468
  var undividedClipShapes = findUndividedClipShapes(clipShapes);
33444
33469
 
33445
33470
  closeArcRoutes(clipShapes, arcs, routeFlags, true, true); // not needed?
@@ -33468,7 +33493,7 @@ ${svg}
33468
33493
  for (var i=0, n=ids.length; i<n; i++) {
33469
33494
  clipArcTouches = 0;
33470
33495
  clipArcUses = 0;
33471
- path = dividePath(ids[i]);
33496
+ path = findPath(ids[i]);
33472
33497
  if (path) {
33473
33498
  // if ring doesn't touch/intersect a clip/erase polygon, check if it is contained
33474
33499
  // if (clipArcTouches === 0) {
@@ -33487,6 +33512,7 @@ ${svg}
33487
33512
  }
33488
33513
  });
33489
33514
 
33515
+
33490
33516
  // Clear pathways of current target shape to hidden/closed
33491
33517
  closeArcRoutes(shape, arcs, routeFlags, true, true, true);
33492
33518
  // Also clear pathways of any clip arcs that were used
@@ -33557,8 +33583,9 @@ ${svg}
33557
33583
  return usable;
33558
33584
  }
33559
33585
 
33560
- // Filter a collection of shapes to exclude paths that contain clip/erase arcs
33561
- // and paths that are hidden (e.g. internal boundaries)
33586
+
33587
+ // Filter a collection of shapes to exclude paths that incorporate parts of
33588
+ // clip/erase polygons and paths that are hidden (e.g. internal boundaries)
33562
33589
  function findUndividedClipShapes(clipShapes) {
33563
33590
  return clipShapes.map(function(shape) {
33564
33591
  var usableParts = [];
@@ -33582,12 +33609,12 @@ ${svg}
33582
33609
  });
33583
33610
  }
33584
33611
 
33585
- // Test if arc is unused in both directions
33586
- // (not testing open/closed or visible/hidden)
33612
+
33587
33613
  function arcIsUnused(id, flags) {
33588
33614
  var abs = absArcId(id),
33589
33615
  flag = flags[abs];
33590
- return (flag & 0x44) === 0;
33616
+ return (flag & 0x88) === 0;
33617
+ // return id < 0 ? (flag & 0x80) === 0 : (flag & 0x8) === 0;
33591
33618
  }
33592
33619
 
33593
33620
  function arcIsVisible(id, flags) {
@@ -33610,7 +33637,7 @@ ${svg}
33610
33637
  enclosedPaths.forEach(function(ids) {
33611
33638
  var path;
33612
33639
  for (var j=0; j<ids.length; j++) {
33613
- path = dividePath(ids[j]);
33640
+ path = findPath(ids[j]);
33614
33641
  if (path) {
33615
33642
  dissolvedPaths.push(path);
33616
33643
  }