mapshaper 0.6.0 → 0.6.2

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.6.0";
3
+ var VERSION = "0.6.2";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -258,7 +258,7 @@
258
258
  '/': '/'
259
259
  };
260
260
  function htmlEscape(s) {
261
- return String(s).replace(/[&<>"'\/]/g, function(s) {
261
+ return String(s).replace(/[&<>"'/]/g, function(s) {
262
262
  return entityMap[s];
263
263
  });
264
264
  }
@@ -901,8 +901,8 @@
901
901
  var type = matches[4];
902
902
  var isString = type == 's',
903
903
  isHex = type == 'x' || type == 'X',
904
- isInt = type == 'd' || type == 'i',
905
- isFloat = type == 'f',
904
+ // isInt = type == 'd' || type == 'i',
905
+ // isFloat = type == 'f',
906
906
  isNumber = !isString;
907
907
 
908
908
  var sign = "",
@@ -961,7 +961,7 @@
961
961
 
962
962
  // Get a function for interpolating formatted values into a string.
963
963
  function formatter(fmt) {
964
- var codeRxp = /%([\',+0]*)([1-9]?)((?:\.[1-9])?)([sdifxX%])/g;
964
+ var codeRxp = /%([',+0]*)([1-9]?)((?:\.[1-9])?)([sdifxX%])/g;
965
965
  var literals = [],
966
966
  formatCodes = [],
967
967
  startIdx = 0,
@@ -3522,7 +3522,7 @@
3522
3522
  if (typeof require == 'function') {
3523
3523
  f = require;
3524
3524
  } else {
3525
- f = function(name) {
3525
+ f = function() {
3526
3526
  // console.error('Unable to load module', name);
3527
3527
  };
3528
3528
  }
@@ -6479,12 +6479,12 @@
6479
6479
  // Accessor function for arcs
6480
6480
  Object.defineProperty(this, 'arcs', {value: arcs});
6481
6481
 
6482
- var toArray = this.toArray = function() {
6482
+ this.toArray = function() {
6483
6483
  var chains = getNodeChains(),
6484
6484
  flags = new Uint8Array(chains.length),
6485
6485
  arr = [];
6486
6486
  utils.forEach(chains, function(nextIdx, thisIdx) {
6487
- var node, x, y, p;
6487
+ var node, p;
6488
6488
  if (flags[thisIdx] == 1) return;
6489
6489
  p = getEndpoint(thisIdx);
6490
6490
  if (!p) return; // endpoints of an excluded arc
@@ -12059,10 +12059,6 @@
12059
12059
  // if point x,y falls on an endpoint
12060
12060
  // Assumes: i <= j
12061
12061
  function getCutPoint(x, y, i, j, xx, yy) {
12062
- var ix = xx[i],
12063
- iy = yy[i],
12064
- jx = xx[j],
12065
- jy = yy[j];
12066
12062
  if (j < i || j > i + 1) {
12067
12063
  error("Out-of-sequence arc ids:", i, j);
12068
12064
  }
@@ -14048,18 +14044,18 @@
14048
14044
  // accept variations on type names (dot, dots, square, squares, hatch, hatches, hatched)
14049
14045
  if (first.startsWith('dot')) {
14050
14046
  parts[0] = 'dots';
14051
- obj = parseDots(parts, str);
14047
+ obj = parseDots(parts);
14052
14048
  } else if (first.startsWith('square')) {
14053
14049
  parts[0] = 'squares';
14054
- obj = parseDots(parts, str);
14050
+ obj = parseDots(parts);
14055
14051
  } else if (first.startsWith('hatch')) {
14056
14052
  parts[0] = 'hatches';
14057
- obj = parseHatches(parts, str);
14053
+ obj = parseHatches(parts);
14058
14054
  } else if (first.startsWith('dash')) {
14059
- obj = parseDashes(parts, str);
14055
+ obj = parseDashes(parts);
14060
14056
  } else if (!isNaN(parseFloat(first))) {
14061
14057
  parts.unshift('hatches');
14062
- obj = parseHatches(parts, str); // hatches is the default, name can be omitted
14058
+ obj = parseHatches(parts); // hatches is the default, name can be omitted
14063
14059
  }
14064
14060
  if (!obj) {
14065
14061
  // consider
@@ -14068,7 +14064,7 @@
14068
14064
  return obj;
14069
14065
  }
14070
14066
 
14071
- function parseDashes(parts, str) {
14067
+ function parseDashes(parts) {
14072
14068
  // format:
14073
14069
  // "dashes" dash-len dash-space width color1 [color2...] space bg-color
14074
14070
  // examples:
@@ -14109,7 +14105,7 @@
14109
14105
  };
14110
14106
  }
14111
14107
 
14112
- function parseHatches(parts, str) {
14108
+ function parseHatches(parts) {
14113
14109
  // format:
14114
14110
  // [hatches] [rotation] width1 color1 [width2 color2 ...]
14115
14111
  // examples:
@@ -14136,7 +14132,7 @@
14136
14132
  return parseInt(str) > 0;
14137
14133
  }
14138
14134
 
14139
- function parseDots(parts, str) {
14135
+ function parseDots(parts) {
14140
14136
  // format:
14141
14137
  // "dots"|"squares" [rotation] size color1 [color2 ...] spacing bg-color
14142
14138
  // examples:
@@ -14300,6 +14296,7 @@
14300
14296
  'stroke-opacity': 'number',
14301
14297
  'stroke-miterlimit': 'number',
14302
14298
  'fill-opacity': 'number',
14299
+ 'vector-effect': null,
14303
14300
  'text-anchor': null
14304
14301
  };
14305
14302
 
@@ -14329,7 +14326,7 @@
14329
14326
  effect: null // e.g. "fade"
14330
14327
  }, stylePropertyTypes);
14331
14328
 
14332
- var commonProperties = 'css,class,opacity,stroke,stroke-width,stroke-dasharray,stroke-opacity,fill-opacity'.split(',');
14329
+ var commonProperties = 'css,class,opacity,stroke,stroke-width,stroke-dasharray,stroke-opacity,fill-opacity,vector-effect'.split(',');
14333
14330
 
14334
14331
  var propertiesBySymbolType = {
14335
14332
  polygon: utils.arrayToIndex(commonProperties.concat('fill', 'fill-pattern')),
@@ -14409,7 +14406,7 @@
14409
14406
  function mightBeExpression(str, fields) {
14410
14407
  fields = fields || [];
14411
14408
  if (fields.indexOf(str.trim()) > -1) return true;
14412
- return /[(){}./*?:&|=\[+-]/.test(str);
14409
+ return /[(){}./*?:&|=[+-]/.test(str);
14413
14410
  }
14414
14411
 
14415
14412
  function getSymbolPropertyAccessor(val, svgName, lyr) {
@@ -14536,7 +14533,7 @@
14536
14533
 
14537
14534
  function importGeoJSONFeatures(features, opts) {
14538
14535
  opts = opts || {};
14539
- return features.map(function(obj, i) {
14536
+ return features.map(function(obj) {
14540
14537
  var geom = obj.type == 'Feature' ? obj.geometry : obj; // could be null
14541
14538
  var geomType = geom && geom.type;
14542
14539
  var msType = GeoJSON.translateGeoJSONType(geomType);
@@ -14852,7 +14849,7 @@
14852
14849
  }
14853
14850
 
14854
14851
  // polyline coords are like GeoJSON MultiLineString coords: an array of 0 or more paths
14855
- function polyline(d, x, y) {
14852
+ function polyline(d) {
14856
14853
  var coords = d.coordinates || [];
14857
14854
  var o = importMultiLineString(coords);
14858
14855
  applyStyleAttributes(o, 'polyline', d);
@@ -14860,7 +14857,7 @@
14860
14857
  }
14861
14858
 
14862
14859
  // polygon coords are an array of rings (and holes), like flattened MultiPolygon coords
14863
- function polygon(d, x, y) {
14860
+ function polygon(d) {
14864
14861
  var coords = d.coordinates || [];
14865
14862
  var o = importPolygon(coords);
14866
14863
  applyStyleAttributes(o, 'polygon', d);
@@ -15407,7 +15404,6 @@ ${svg}
15407
15404
  var geojson = exportDatasetAsGeoJSON(d, opts);
15408
15405
  var features = geojson.features || geojson.geometries || (geojson.type ? [geojson] : []);
15409
15406
  var children = importGeoJSONFeatures(features, opts);
15410
- var data;
15411
15407
  if (opts.svg_data && lyr.data) {
15412
15408
  addDataAttributesToSVG(children, lyr.data, opts.svg_data);
15413
15409
  }
@@ -16336,7 +16332,7 @@ ${svg}
16336
16332
  return readFixedWidthRecordsFromString(str, opts);
16337
16333
  }
16338
16334
 
16339
- function readFixedWidthRecordsFromString(str, ops) {
16335
+ function readFixedWidthRecordsFromString(str) {
16340
16336
  var fields = parseFixedWidthInfo(str.substring(0, 2000));
16341
16337
  if (!fields) return [];
16342
16338
  var lines = utils.splitLines(str);
@@ -16483,11 +16479,6 @@ ${svg}
16483
16479
  return formatRow(rec);
16484
16480
  }
16485
16481
 
16486
- function formatDelimHeader(fields, delim) {
16487
- var formatValue = getDelimValueFormatter(delim);
16488
- return fields.map(formatValue).join(delim);
16489
- }
16490
-
16491
16482
  function getDelimRowFormatter(fields, delim, opts) {
16492
16483
  var formatValue = getDelimValueFormatter(delim, opts);
16493
16484
  return function(rec) {
@@ -18170,8 +18161,7 @@ ${svg}
18170
18161
  // @chars String of chars to look for in @str
18171
18162
  function getCharScore(str, chars) {
18172
18163
  var index = {},
18173
- count = 0,
18174
- score;
18164
+ count = 0;
18175
18165
  str = str.toLowerCase();
18176
18166
  for (var i=0, n=chars.length; i<n; i++) {
18177
18167
  index[chars[i]] = 1;
@@ -18192,7 +18182,7 @@ ${svg}
18192
18182
  // TODO: remove duplication with importJSON()
18193
18183
  var readFromFile = !data.content && data.content !== '',
18194
18184
  content = data.content,
18195
- filter, reader, records, delimiter, table, encoding;
18185
+ reader, records, delimiter, table, encoding;
18196
18186
  opts = opts || {};
18197
18187
 
18198
18188
  // // read content of all but very large files into a buffer
@@ -18434,43 +18424,19 @@ ${svg}
18434
18424
  }
18435
18425
  }
18436
18426
 
18437
- // var intervalStr = o.interval;
18438
- // if (intervalStr) {
18439
- // o.interval = Number(intervalStr);
18440
- // if (o.interval >= 0 === false) {
18441
- // error(utils.format("Out-of-range interval value: %s", intervalStr));
18442
- // }
18443
- // }
18444
-
18445
18427
  if (!o.interval && !o.percentage && !o.resolution) {
18446
18428
  error("Command requires an interval, percentage or resolution parameter");
18447
18429
  }
18448
18430
  }
18449
18431
 
18450
18432
  function validateProjOpts(cmd) {
18451
- var _ = cmd._,
18452
- proj4 = [];
18433
+ var _ = cmd._;
18453
18434
 
18454
18435
  if (_.length > 0 && !cmd.options.crs) {
18455
18436
  cmd.options.crs = _.join(' ');
18456
18437
  _ = [];
18457
18438
  }
18458
18439
 
18459
- // separate proj4 options
18460
- // _ = _.filter(function(arg) {
18461
- // if (/^\+[a-z]/i.test(arg)) {
18462
- // proj4.push(arg);
18463
- // return false;
18464
- // }
18465
- // return true;
18466
- // });
18467
-
18468
- // if (proj4.length > 0) {
18469
- // cmd.options.crs = proj4.join(' ');
18470
- // } else if (_.length > 0) {
18471
- // cmd.options.crs = _.shift();
18472
- // }
18473
-
18474
18440
  if (_.length > 0) {
18475
18441
  error("Received one or more unexpected parameters: " + _.join(', '));
18476
18442
  }
@@ -18565,7 +18531,7 @@ ${svg}
18565
18531
  }
18566
18532
  }
18567
18533
 
18568
- var assignmentRxp = /^([a-z0-9_+-]+)=(?!\=)(.*)$/i; // exclude ==
18534
+ var assignmentRxp = /^([a-z0-9_+-]+)=(?!=)(.*)$/i; // exclude ==
18569
18535
 
18570
18536
  function splitShellTokens(str) {
18571
18537
  var BAREWORD = '([^\'"\\s])+';
@@ -20953,6 +20919,10 @@ ${svg}
20953
20919
  // describe: (0-1) inset grid shapes by a percentage
20954
20920
  type: 'number'
20955
20921
  })
20922
+ .option('aligned', {
20923
+ // describe: all grids of a given cell size will be aligned
20924
+ type: 'flag'
20925
+ })
20956
20926
  .option('calc', calcOpt)
20957
20927
  .option('name', nameOpt)
20958
20928
  .option('target', targetOpt)
@@ -21099,6 +21069,9 @@ ${svg}
21099
21069
  })
21100
21070
  .option('target', targetOpt);
21101
21071
 
21072
+ parser.command('stop')
21073
+ .describe('stop processing (skip remaining commands)');
21074
+
21102
21075
  parser.section('Informational commands');
21103
21076
 
21104
21077
  parser.command('calc')
@@ -22760,7 +22733,6 @@ ${svg}
22760
22733
  shapes = [], // topological ids
22761
22734
  types = [],
22762
22735
  dataNulls = 0,
22763
- shapeNulls = 0,
22764
22736
  collectionType = null,
22765
22737
  shapeId;
22766
22738
 
@@ -22777,15 +22749,12 @@ ${svg}
22777
22749
  if (geom.type) {
22778
22750
  this.addShape(geom);
22779
22751
  }
22780
- if (shapes[shapeId] === null) {
22781
- shapeNulls++;
22782
- }
22783
22752
  };
22784
22753
 
22785
22754
  this.addShape = function(geom) {
22786
22755
  var curr = shapes[shapeId];
22787
22756
  var type = GeoJSON.translateGeoJSONType(geom.type);
22788
- var shape, importer;
22757
+ var shape;
22789
22758
  if (geom.type == "GeometryCollection") {
22790
22759
  geom.geometries.forEach(this.addShape, this);
22791
22760
  } else if (type) {
@@ -24065,12 +24034,12 @@ ${svg}
24065
24034
  function Job(catalog) {
24066
24035
  var currentCmd;
24067
24036
 
24068
- var job = {
24037
+ var job = {
24069
24038
  catalog: catalog || new Catalog(),
24070
24039
  defs: {},
24071
24040
  settings: {},
24072
24041
  input_files: []
24073
- };
24042
+ };
24074
24043
 
24075
24044
  job.initSettings = function(o) {
24076
24045
  job.settings = o;
@@ -27125,10 +27094,6 @@ ${svg}
27125
27094
  // polyline output could be used for debugging
27126
27095
  var outputGeom = opts.output_geometry == 'polyline' ? 'polyline' : 'polygon';
27127
27096
 
27128
- function polygonCoords(ring) {
27129
- return [ring];
27130
- }
27131
-
27132
27097
  function pathBufferCoords(pathArcs, dist) {
27133
27098
  var pathCoords = maker(pathArcs, dist);
27134
27099
  var revPathArcs;
@@ -27158,13 +27123,9 @@ ${svg}
27158
27123
  var backtrackSteps = opts.backtrack >= 0 ? opts.backtrack : 50;
27159
27124
  var pathIter = new ShapeIter(arcs);
27160
27125
  var capStyle = opts.cap_style || 'round'; // expect 'round' or 'flat'
27161
- var tolerance;
27126
+ // var tolerance;
27162
27127
  // TODO: implement other join styles than round
27163
27128
 
27164
- function updateTolerance(dist) {
27165
-
27166
- }
27167
-
27168
27129
  function addRoundJoin(arr, x, y, startDir, angle, dist) {
27169
27130
  var increment = 10;
27170
27131
  var endDir = startDir + angle;
@@ -27175,15 +27136,15 @@ ${svg}
27175
27136
  }
27176
27137
  }
27177
27138
 
27178
- function addRoundJoin2(arr, x, y, startDir, angle, dist) {
27179
- var increment = 10;
27180
- var endDir = startDir + angle;
27181
- var dir = startDir + increment;
27182
- while (dir < endDir) {
27183
- addBufferVertex(arr, geod(x, y, dir, dist), backtrackSteps);
27184
- dir += increment;
27185
- }
27186
- }
27139
+ // function addRoundJoin2(arr, x, y, startDir, angle, dist) {
27140
+ // var increment = 10;
27141
+ // var endDir = startDir + angle;
27142
+ // var dir = startDir + increment;
27143
+ // while (dir < endDir) {
27144
+ // addBufferVertex(arr, geod(x, y, dir, dist), backtrackSteps);
27145
+ // dir += increment;
27146
+ // }
27147
+ // }
27187
27148
 
27188
27149
  // Test if two points are within a snapping tolerance
27189
27150
  // TODO: calculate the tolerance more sensibly
@@ -27430,15 +27391,14 @@ ${svg}
27430
27391
  function getPathBufferMaker2(arcs, geod, getBearing, opts) {
27431
27392
  var backtrackSteps = opts.backtrack >= 0 ? opts.backtrack : 50;
27432
27393
  var pathIter = new ShapeIter(arcs);
27433
- var capStyle = opts.cap_style || 'round'; // expect 'round' or 'flat'
27434
- var tolerance;
27394
+ // var capStyle = opts.cap_style || 'round'; // expect 'round' or 'flat'
27435
27395
  var partials, left, center;
27436
27396
  var bounds;
27437
27397
  // TODO: implement other join styles than round
27438
27398
 
27439
- function updateTolerance(dist) {
27399
+ // function updateTolerance(dist) {
27440
27400
 
27441
- }
27401
+ // }
27442
27402
 
27443
27403
  function addRoundJoin(x, y, startDir, angle, dist) {
27444
27404
  var increment = 10;
@@ -27482,24 +27442,24 @@ ${svg}
27482
27442
  }
27483
27443
  }
27484
27444
 
27485
- function makeCap(x, y, direction, dist) {
27486
- if (capStyle == 'flat') {
27487
- return [[x, y]];
27488
- }
27489
- return makeRoundCap(x, y, direction, dist);
27490
- }
27445
+ // function makeCap(x, y, direction, dist) {
27446
+ // if (capStyle == 'flat') {
27447
+ // return [[x, y]];
27448
+ // }
27449
+ // return makeRoundCap(x, y, direction, dist);
27450
+ // }
27491
27451
 
27492
- function makeRoundCap(x, y, segmentDir, dist) {
27493
- var points = [];
27494
- var increment = 10;
27495
- var startDir = segmentDir - 90;
27496
- var angle = increment;
27497
- while (angle < 180) {
27498
- points.push(geod(x, y, startDir + angle, dist));
27499
- angle += increment;
27500
- }
27501
- return points;
27502
- }
27452
+ // function makeRoundCap(x, y, segmentDir, dist) {
27453
+ // var points = [];
27454
+ // var increment = 10;
27455
+ // var startDir = segmentDir - 90;
27456
+ // var angle = increment;
27457
+ // while (angle < 180) {
27458
+ // points.push(geod(x, y, startDir + angle, dist));
27459
+ // angle += increment;
27460
+ // }
27461
+ // return points;
27462
+ // }
27503
27463
 
27504
27464
  // get angle between two extruded segments in degrees
27505
27465
  // positive angle means join in convex (range: 0-180 degrees)
@@ -27596,18 +27556,20 @@ ${svg}
27596
27556
  }
27597
27557
 
27598
27558
  return function(path, dist) {
27599
- var x0, y0, x1, y1, x2, y2;
27559
+ // var x0, y0;
27560
+ var x1, y1, x2, y2;
27600
27561
  var p1, p2;
27601
- var bearing, prevBearing, firstBearing, joinAngle;
27562
+ // var firstBearing;
27563
+ var bearing, prevBearing, joinAngle;
27602
27564
  partials = [];
27603
27565
  left = [];
27604
27566
  center = [];
27605
27567
  pathIter.init(path);
27606
27568
 
27607
- if (pathIter.hasNext()) {
27608
- x0 = x2 = pathIter.x;
27609
- y0 = y2 = pathIter.y;
27610
- }
27569
+ // if (pathIter.hasNext()) {
27570
+ // x0 = x2 = pathIter.x;
27571
+ // y0 = y2 = pathIter.y;
27572
+ // }
27611
27573
  while (pathIter.hasNext()) {
27612
27574
  // TODO: use a tolerance
27613
27575
  if (pathIter.x === x2 && pathIter.y === y2) continue; // skip duplicate points
@@ -27624,9 +27586,9 @@ ${svg}
27624
27586
 
27625
27587
  if (center.length === 0) {
27626
27588
  // first loop, second point in this partial
27627
- if (partials.length === 0) {
27628
- firstBearing = bearing;
27629
- }
27589
+ // if (partials.length === 0) {
27590
+ // firstBearing = bearing;
27591
+ // }
27630
27592
  left.push(p1, p2);
27631
27593
  center.push([x1, y1], [x2, y2]);
27632
27594
  } else {
@@ -28207,7 +28169,7 @@ ${svg}
28207
28169
  rings.push([
28208
28170
  [[180, 90], [180, -90], [0, -90], [-180, -90], [-180, 90], [0, 90], [180, 90]],
28209
28171
  coords
28210
- ]);
28172
+ ]);
28211
28173
  } else {
28212
28174
  rings.push([coords]);
28213
28175
  }
@@ -34899,6 +34861,7 @@ ${svg}
34899
34861
  // }).join(",") + "}");
34900
34862
  // };
34901
34863
 
34864
+ // Removes points that are far from other points
34902
34865
  cmd.filterPoints = function(lyr, dataset, opts) {
34903
34866
  requireSinglePointLayer(lyr);
34904
34867
  if (opts.group_interval > 0 === false) {
@@ -34913,7 +34876,7 @@ ${svg}
34913
34876
  var index = new Uint8Array(points.length);
34914
34877
  var a, b, c, ai, bi, ci;
34915
34878
  for (var i=0, n=triangles.length; i<n; i+=3) {
34916
- // a, b, c: triangle verticies in CCW order
34879
+ // a, b, c: triangle vertices in CCW order
34917
34880
  ai = triangles[i];
34918
34881
  bi = triangles[i+1];
34919
34882
  ci = triangles[i+2];
@@ -36085,7 +36048,7 @@ ${svg}
36085
36048
  var arcId = o.arcId,
36086
36049
  key = classify(arcId),
36087
36050
  isContinuation, line;
36088
- if (!!key) {
36051
+ if (key) {
36089
36052
  line = key in index ? index[key] : null;
36090
36053
  isContinuation = key == prevKey && o.shapeId == prev.shapeId && o.partId == prev.partId;
36091
36054
  if (!line) {
@@ -36765,6 +36728,14 @@ ${svg}
36765
36728
  job.control = null;
36766
36729
  }
36767
36730
 
36731
+ function stopJob(job) {
36732
+ getState(job).stopped = true;
36733
+ }
36734
+
36735
+ function jobIsStopped(job) {
36736
+ return getState(job).stopped === true;
36737
+ }
36738
+
36768
36739
  function inControlBlock(job) {
36769
36740
  return !!getState(job).inControlBlock;
36770
36741
  }
@@ -36833,6 +36804,7 @@ ${svg}
36833
36804
 
36834
36805
  function skipCommand(cmdName, job) {
36835
36806
  // allow all control commands to run
36807
+ if (jobIsStopped(job)) return true;
36836
36808
  if (isControlFlowCommand(cmdName)) return false;
36837
36809
  return inControlBlock(job) && !inActiveBranch(job);
36838
36810
  }
@@ -38761,7 +38733,7 @@ ${svg}
38761
38733
  stop('Expected a non-negative interval parameter');
38762
38734
  }
38763
38735
  if (opts.radius > 0 === false) {
38764
- stop('Expected a non-negative radius parameter');
38736
+ // stop('Expected a non-negative radius parameter');
38765
38737
  }
38766
38738
  // var bbox = getLayerBounds(pointLyr).toArray();
38767
38739
  // Use target dataset, so grids are aligned between layers
@@ -38789,27 +38761,24 @@ ${svg}
38789
38761
  };
38790
38762
 
38791
38763
  function getPolygonDataset(pointLyr, gridBBox, opts) {
38792
- var interval = opts.interval;
38793
38764
  var points = getPointsInLayer(pointLyr);
38794
- var grid = getGridData(gridBBox, interval);
38795
- var lookup = getPointIndex(points, grid, opts.radius);
38796
- var n = grid.cells();
38765
+ var cellSize = opts.interval;
38766
+ var grid = getGridData(gridBBox, cellSize, opts);
38767
+ var pointCircleRadius = getPointCircleRadius(opts);
38768
+ var findPointIdsByCellId = getPointIndex(points, grid, pointCircleRadius);
38797
38769
  var geojson = {
38798
38770
  type: 'FeatureCollection',
38799
38771
  features: []
38800
38772
  };
38801
- var calc = null;
38802
- var cands, center, weight, d;
38803
- if (opts.calc) {
38804
- calc = getJoinCalc(pointLyr.data, opts.calc);
38805
- }
38773
+ var calc = opts.calc ? getJoinCalc(pointLyr.data, opts.calc) : null;
38774
+ var candidateIds, weights, center, weight, d;
38806
38775
 
38807
- for (var i=0; i<n; i++) {
38808
- cands = lookup(i);
38809
- if (!cands.length) continue;
38776
+ for (var i=0, n=grid.cells(); i<n; i++) {
38777
+ candidateIds = findPointIdsByCellId(i);
38778
+ if (!candidateIds.length) continue;
38810
38779
  center = grid.idxToPoint(i);
38811
- d = calcCellProperties(center, cands, points, calc, opts);
38812
- // weight = calcCellWeight(center, cands, points, opts);
38780
+ weights = calcWeights(center, cellSize, points, candidateIds, pointCircleRadius);
38781
+ d = calcCellProperties(candidateIds, weights, calc);
38813
38782
  if (d.weight > 0.05 === false) continue;
38814
38783
  d.id = i;
38815
38784
  geojson.features.push({
@@ -38818,44 +38787,43 @@ ${svg}
38818
38787
  geometry: makeCellPolygon(i, grid, opts)
38819
38788
  });
38820
38789
  }
38821
- var dataset = importGeoJSON(geojson, {});
38822
- return dataset;
38790
+ return importGeoJSON(geojson, {});
38823
38791
  }
38824
38792
 
38825
- function calcCellProperties(center, cands, points, calc, opts) {
38826
- // radius of circle with same area as the cell
38827
- var interval = opts.interval;
38828
- var radius = interval * Math.sqrt(1 / Math.PI);
38829
- var circleArea = Math.PI * opts.radius * opts.radius;
38830
- var cellArea = interval * interval;
38831
- var ids = [];
38832
- var totArea = 0;
38833
- var intersection;
38834
- for (var i=0; i<cands.length; i++) {
38835
- intersection = twoCircleIntersection(center, radius, points[cands[i]], opts.radius);
38836
- if (intersection > 0 === false) continue;
38837
- totArea += intersection;
38838
- ids.push(cands[i]);
38839
- }
38840
- var d = {weight: totArea / cellArea};
38793
+ function getPointCircleRadius(opts) {
38794
+ var cellRadius = opts.interval * Math.sqrt(1 / Math.PI);
38795
+ return opts.radius > 0 ? opts.radius : cellRadius;
38796
+ }
38797
+
38798
+ function calcCellProperties(pointIds, weights, calc) {
38799
+ var hitIds = [];
38800
+ var weight = 0;
38801
+ var partial;
38802
+ var d;
38803
+ for (var i=0; i<pointIds.length; i++) {
38804
+ partial = weights[i];
38805
+ if (partial > 0 === false) continue;
38806
+ weight += partial;
38807
+ hitIds.push(pointIds[i]);
38808
+ }
38809
+ d = {weight: weight};
38841
38810
  if (calc) {
38842
- calc(ids, d);
38811
+ calc(hitIds, d);
38843
38812
  }
38844
38813
  return d;
38845
38814
  }
38846
38815
 
38847
- // function calcCellWeight(center, ids, points, opts) {
38848
- // // radius of circle with same area as the cell
38849
- // var interval = opts.interval;
38850
- // var radius = interval * Math.sqrt(1 / Math.PI);
38851
- // var circleArea = Math.PI * opts.radius * opts.radius;
38852
- // var cellArea = interval * interval;
38853
- // var totArea = 0;
38854
- // for (var i=0; i<ids.length; i++) {
38855
- // totArea += twoCircleIntersection(center, radius, points[ids[i]], opts.radius);
38856
- // }
38857
- // return totArea / cellArea;
38858
- // }
38816
+ function calcWeights(cellCenter, cellSize, points, pointIds, pointRadius) {
38817
+ var weights = [];
38818
+ var cellRadius = cellSize * Math.sqrt(1 / Math.PI); // radius of circle with same area as cell
38819
+ var cellArea = cellSize * cellSize;
38820
+ var w;
38821
+ for (var i=0; i<pointIds.length; i++) {
38822
+ w = twoCircleIntersection(cellCenter, cellRadius, points[pointIds[i]], pointRadius) / cellArea;
38823
+ weights.push(w);
38824
+ }
38825
+ return weights;
38826
+ }
38859
38827
 
38860
38828
  // Source: https://diego.assencio.com/?index=8d6ca3d82151bad815f78addf9b5c1c6
38861
38829
  function twoCircleIntersection(c1, r1, c2, r2) {
@@ -38910,10 +38878,19 @@ ${svg}
38910
38878
  return function(i) {
38911
38879
  if (!gridIndex.hasId(i)) return empty;
38912
38880
  var bbox = grid.idxToBBox(i);
38913
- return bboxIndex.search.apply(bboxIndex, bbox);
38881
+ var indices = bboxIndex.search.apply(bboxIndex, bbox);
38882
+ return indices;
38914
38883
  };
38915
38884
  }
38916
38885
 
38886
+ function getPointsByIndex(points, indices) {
38887
+ var arr = [];
38888
+ for (var i=0; i<indices.length; i++) {
38889
+ arr.push(points[indices[i]]);
38890
+ }
38891
+ return arr;
38892
+ }
38893
+
38917
38894
  function addPointToGridIndex(p, index, grid) {
38918
38895
  var i = grid.pointToIdx(p);
38919
38896
  var c = grid.idxToCol(i);
@@ -38939,23 +38916,52 @@ ${svg}
38939
38916
  return [p[0] - radius, p[1] - radius, p[0] + radius, p[1] + radius];
38940
38917
  }
38941
38918
 
38942
- function getGridInterpolator(bbox, interval) {
38943
- var sparseArr = [];
38944
- var grid = getGridData(bbox, interval);
38945
-
38946
- }
38947
-
38948
- // TODO: put this in a separate file, use it for other grid-based commands
38949
- // like -dots
38950
- function getGridData(bbox, interval) {
38951
- var xmin = bbox[0] - interval;
38952
- var ymin = bbox[1] - interval;
38953
- var xmax = bbox[2] + interval;
38954
- var ymax = bbox[3] + interval;
38955
- var w = xmax - xmin;
38956
- var h = ymax - ymin;
38957
- var cols = Math.ceil(w / interval);
38958
- var rows = Math.ceil(h / interval);
38919
+ // grid boundaries includes the origin
38920
+ // (this way, grids calculated from different sets of points will all align)
38921
+ function getAlignedRange(minCoord, maxCoord, interval) {
38922
+ var idx = Math.floor(minCoord / interval) - 1;
38923
+ var idx2 = Math.ceil(maxCoord / interval) + 1;
38924
+ return [idx * interval, idx2 * interval];
38925
+ }
38926
+
38927
+ function getCenteredRange(minCoord, maxCoord, interval) {
38928
+ var w = maxCoord - minCoord;
38929
+ var w2 = Math.ceil(w / interval) * interval;
38930
+ var pad = (w2 - w) / 2 + interval;
38931
+ return [minCoord - pad, maxCoord + pad];
38932
+ }
38933
+
38934
+ function getAlignedGridBounds(bbox, interval) {
38935
+ var xx = getAlignedRange(bbox[0], bbox[2], interval);
38936
+ var yy = getAlignedRange(bbox[1], bbox[3], interval);
38937
+ return [xx[0], yy[0], xx[1], yy[1]];
38938
+ }
38939
+
38940
+ function getCenteredGridBounds(bbox, interval) {
38941
+ var xx = getCenteredRange(bbox[0], bbox[2], interval);
38942
+ var yy = getCenteredRange(bbox[1], bbox[3], interval);
38943
+ return [xx[0], yy[0], xx[1], yy[1]];
38944
+ }
38945
+
38946
+ // TODO: Use this function for other grid-based commands
38947
+ function getGridData(bbox, interval, opts) {
38948
+ var extent = opts && opts.aligned ?
38949
+ getAlignedGridBounds(bbox, interval) :
38950
+ getCenteredGridBounds(bbox, interval);
38951
+ var xmin = extent[0];
38952
+ var ymin = extent[1];
38953
+ var w = extent[2] - xmin;
38954
+ var h = extent[3] - ymin;
38955
+ var cols = Math.round(w / interval);
38956
+ var rows = Math.round(h / interval);
38957
+ // var xmin = bbox[0] - interval;
38958
+ // var ymin = bbox[1] - interval;
38959
+ // var xmax = bbox[2] + interval;
38960
+ // var ymax = bbox[3] + interval;
38961
+ // var w = xmax - xmin;
38962
+ // var h = ymax - ymin;
38963
+ // var cols = Math.ceil(w / interval);
38964
+ // var rows = Math.ceil(h / interval);
38959
38965
  function size() {
38960
38966
  return [cols, rows];
38961
38967
  }
@@ -40493,6 +40499,10 @@ ${svg}
40493
40499
  getSplitNameFunction: getSplitNameFunction
40494
40500
  });
40495
40501
 
40502
+ cmd.stop = function(job) {
40503
+ stopJob(job);
40504
+ };
40505
+
40496
40506
  cmd.svgStyle = function(lyr, dataset, opts) {
40497
40507
  var filter;
40498
40508
  if (!lyr.data) {
@@ -40638,10 +40648,10 @@ ${svg}
40638
40648
  dy = stemLen * Math.cos(theta / 2);
40639
40649
 
40640
40650
  if (stickArrow) {
40641
- stem = getCurvedStemCoords(-ax, -ay, dx, dy, theta);
40651
+ stem = getCurvedStemCoords(-ax, -ay, dx, dy);
40642
40652
  } else {
40643
- var leftStem = getCurvedStemCoords(-ax, -ay, -stemDx + dx, dy, theta);
40644
- var rightStem = getCurvedStemCoords(ax, ay, stemDx + dx, dy, theta);
40653
+ var leftStem = getCurvedStemCoords(-ax, -ay, -stemDx + dx, dy);
40654
+ var rightStem = getCurvedStemCoords(ax, ay, stemDx + dx, dy);
40645
40655
  stem = leftStem.concat(rightStem.reverse());
40646
40656
  }
40647
40657
 
@@ -40685,10 +40695,10 @@ ${svg}
40685
40695
  return coords;
40686
40696
  }
40687
40697
 
40688
- function calcStraightArrowCoords(stemLen, headLen, stemDx, headDx, baseDx) {
40689
- return [[baseDx, 0], [stemDx, stemLen], [headDx, stemLen], [0, stemLen + headLen],
40690
- [-headDx, stemLen], [-stemDx, stemLen], [-baseDx, 0], [baseDx, 0]];
40691
- }
40698
+ // function calcStraightArrowCoords(stemLen, headLen, stemDx, headDx, baseDx) {
40699
+ // return [[baseDx, 0], [stemDx, stemLen], [headDx, stemLen], [0, stemLen + headLen],
40700
+ // [-headDx, stemLen], [-stemDx, stemLen], [-baseDx, 0], [baseDx, 0]];
40701
+ // }
40692
40702
 
40693
40703
  function calcArrowSize(d, stickArrow) {
40694
40704
  // don't display arrows with negative length
@@ -40755,7 +40765,7 @@ ${svg}
40755
40765
 
40756
40766
  // ax, ay: point on the base
40757
40767
  // bx, by: point on the stem
40758
- function getCurvedStemCoords(ax, ay, bx, by, theta0) {
40768
+ function getCurvedStemCoords(ax, ay, bx, by) {
40759
40769
  // case: curved side intrudes into head (because stem is too short)
40760
40770
  if (ay > by) {
40761
40771
  return [[ax * by / ay, by]];
@@ -41478,7 +41488,7 @@ ${svg}
41478
41488
  return name == 'graticule' || name == 'i' || name == 'help' ||
41479
41489
  name == 'point-grid' || name == 'shape' || name == 'rectangle' ||
41480
41490
  name == 'include' || name == 'print' || name == 'comment' || name == 'if' || name == 'elif' ||
41481
- name == 'else' || name == 'endif';
41491
+ name == 'else' || name == 'endif' || name == 'stop';
41482
41492
  }
41483
41493
 
41484
41494
  function runCommand(command, job, cb) {
@@ -41808,6 +41818,9 @@ ${svg}
41808
41818
  } else if (name == 'split') {
41809
41819
  outputLayers = applyCommandToEachLayer(cmd.splitLayer, targetLayers, opts.expression, opts);
41810
41820
 
41821
+ } else if (name == 'stop') {
41822
+ cmd.stop(job);
41823
+
41811
41824
  } else if (name == 'split-on-grid') {
41812
41825
  outputLayers = applyCommandToEachLayer(cmd.splitLayerOnGrid, targetLayers, arcs, opts);
41813
41826
 
@@ -42573,7 +42586,6 @@ ${svg}
42573
42586
  // so they can be run by tests and by the GUI.
42574
42587
  // TODO: rewrite tests to import functions directly from modules,
42575
42588
  // export only functions called by the GUI.
42576
-
42577
42589
  var internal = {};
42578
42590
 
42579
42591
  internal.svg = Object.assign({}, SvgStringify, SvgPathUtils, GeojsonToSvg, SvgLabels, SvgSymbols);