mapshaper 0.6.43 → 0.6.45
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/bin/mapshaper-gui +9 -2
- package/mapshaper.js +336 -192
- package/package.json +2 -2
- package/www/index.html +1 -1
- package/www/mapshaper-gui.js +80 -12
- package/www/mapshaper.js +336 -192
- package/www/page.css +9 -5
package/www/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.6.
|
|
3
|
+
var VERSION = "0.6.45";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
get default () { return utils; },
|
|
9
9
|
get getUniqueName () { return getUniqueName; },
|
|
10
10
|
get isFunction () { return isFunction; },
|
|
11
|
+
get isPromise () { return isPromise; },
|
|
11
12
|
get isObject () { return isObject; },
|
|
12
13
|
get clamp () { return clamp; },
|
|
13
14
|
get isArray () { return isArray; },
|
|
@@ -147,6 +148,10 @@
|
|
|
147
148
|
return typeof obj == 'function';
|
|
148
149
|
}
|
|
149
150
|
|
|
151
|
+
function isPromise(arg) {
|
|
152
|
+
return arg ? isFunction(arg.then) : false;
|
|
153
|
+
}
|
|
154
|
+
|
|
150
155
|
function isObject(obj) {
|
|
151
156
|
return obj === Object(obj); // via underscore
|
|
152
157
|
}
|
|
@@ -1877,12 +1882,67 @@
|
|
|
1877
1882
|
arcs.updateVertexData(nn, xx2, yy2, zz2);
|
|
1878
1883
|
}
|
|
1879
1884
|
|
|
1885
|
+
function countFilteredVertices(zz, zlimit) {
|
|
1886
|
+
var count = 0;
|
|
1887
|
+
for (var i=0, n = zz.length; i<n; i++) {
|
|
1888
|
+
if (zz[i] >= zlimit) count++;
|
|
1889
|
+
}
|
|
1890
|
+
return count;
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
function filterVertexData(o, zlimit) {
|
|
1894
|
+
if (!o.zz) error('Expected simplification data');
|
|
1895
|
+
var xx = o.xx,
|
|
1896
|
+
yy = o.yy,
|
|
1897
|
+
zz = o.zz,
|
|
1898
|
+
len2 = countFilteredVertices(zz, zlimit),
|
|
1899
|
+
arcCount = o.nn.length,
|
|
1900
|
+
xx2 = new Float64Array(len2),
|
|
1901
|
+
yy2 = new Float64Array(len2),
|
|
1902
|
+
zz2 = new Float64Array(len2),
|
|
1903
|
+
nn2 = new Int32Array(arcCount),
|
|
1904
|
+
i = 0, i2 = 0,
|
|
1905
|
+
n, n2;
|
|
1906
|
+
|
|
1907
|
+
for (var arcId=0; arcId < arcCount; arcId++) {
|
|
1908
|
+
n2 = 0;
|
|
1909
|
+
n = o.nn[arcId];
|
|
1910
|
+
for (var end = i+n; i < end; i++) {
|
|
1911
|
+
if (zz[i] >= zlimit) {
|
|
1912
|
+
xx2[i2] = xx[i];
|
|
1913
|
+
yy2[i2] = yy[i];
|
|
1914
|
+
zz2[i2] = zz[i];
|
|
1915
|
+
i2++;
|
|
1916
|
+
n2++;
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
if (n2 == 1) {
|
|
1920
|
+
error("Collapsed arc");
|
|
1921
|
+
// This should not happen (endpoints should be z == Infinity)
|
|
1922
|
+
// Could handle like this, instead of throwing an error:
|
|
1923
|
+
// n2 = 0;
|
|
1924
|
+
// xx2.pop();
|
|
1925
|
+
// yy2.pop();
|
|
1926
|
+
// zz2.pop();
|
|
1927
|
+
}
|
|
1928
|
+
nn2[arcId] = n2;
|
|
1929
|
+
}
|
|
1930
|
+
return {
|
|
1931
|
+
xx: xx2,
|
|
1932
|
+
yy: yy2,
|
|
1933
|
+
zz: zz2,
|
|
1934
|
+
nn: nn2
|
|
1935
|
+
};
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1880
1938
|
var ArcUtils = /*#__PURE__*/Object.freeze({
|
|
1881
1939
|
__proto__: null,
|
|
1882
1940
|
absArcId: absArcId,
|
|
1883
1941
|
calcArcBounds: calcArcBounds,
|
|
1884
1942
|
deleteVertex: deleteVertex,
|
|
1885
|
-
insertVertex: insertVertex
|
|
1943
|
+
insertVertex: insertVertex,
|
|
1944
|
+
countFilteredVertices: countFilteredVertices,
|
|
1945
|
+
filterVertexData: filterVertexData
|
|
1886
1946
|
});
|
|
1887
1947
|
|
|
1888
1948
|
var WGS84 = {
|
|
@@ -5354,17 +5414,6 @@
|
|
|
5354
5414
|
initZData(zz || null);
|
|
5355
5415
|
};
|
|
5356
5416
|
|
|
5357
|
-
// Give access to raw data arrays...
|
|
5358
|
-
this.getVertexData = function() {
|
|
5359
|
-
return {
|
|
5360
|
-
xx: _xx,
|
|
5361
|
-
yy: _yy,
|
|
5362
|
-
zz: _zz,
|
|
5363
|
-
bb: _bb,
|
|
5364
|
-
nn: _nn,
|
|
5365
|
-
ii: _ii
|
|
5366
|
-
};
|
|
5367
|
-
};
|
|
5368
5417
|
|
|
5369
5418
|
this.getCopy = function() {
|
|
5370
5419
|
var copy = new ArcCollection(new Int32Array(_nn), new Float64Array(_xx),
|
|
@@ -5376,55 +5425,28 @@
|
|
|
5376
5425
|
return copy;
|
|
5377
5426
|
};
|
|
5378
5427
|
|
|
5428
|
+
|
|
5429
|
+
// Give access to raw data arrays...
|
|
5430
|
+
this.getVertexData = getVertexData;
|
|
5431
|
+
|
|
5432
|
+
function getVertexData() {
|
|
5433
|
+
return {
|
|
5434
|
+
xx: _xx,
|
|
5435
|
+
yy: _yy,
|
|
5436
|
+
zz: _zz,
|
|
5437
|
+
bb: _bb,
|
|
5438
|
+
nn: _nn,
|
|
5439
|
+
ii: _ii
|
|
5440
|
+
};
|
|
5441
|
+
}
|
|
5442
|
+
|
|
5379
5443
|
function getFilteredPointCount() {
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
var count = 0;
|
|
5383
|
-
for (var i=0, n = zz.length; i<n; i++) {
|
|
5384
|
-
if (zz[i] >= z) count++;
|
|
5385
|
-
}
|
|
5386
|
-
return count;
|
|
5444
|
+
if (!_zz || !_zlimit) return this.getPointCount();
|
|
5445
|
+
return countFilteredVertices(_zz, _zlimit);
|
|
5387
5446
|
}
|
|
5388
5447
|
|
|
5389
5448
|
function getFilteredVertexData() {
|
|
5390
|
-
|
|
5391
|
-
var arcCount = _nn.length;
|
|
5392
|
-
var xx2 = new Float64Array(len2),
|
|
5393
|
-
yy2 = new Float64Array(len2),
|
|
5394
|
-
zz2 = new Float64Array(len2),
|
|
5395
|
-
nn2 = new Int32Array(arcCount),
|
|
5396
|
-
i=0, i2 = 0,
|
|
5397
|
-
n, n2;
|
|
5398
|
-
|
|
5399
|
-
for (var arcId=0; arcId < arcCount; arcId++) {
|
|
5400
|
-
n2 = 0;
|
|
5401
|
-
n = _nn[arcId];
|
|
5402
|
-
for (var end = i+n; i < end; i++) {
|
|
5403
|
-
if (_zz[i] >= _zlimit) {
|
|
5404
|
-
xx2[i2] = _xx[i];
|
|
5405
|
-
yy2[i2] = _yy[i];
|
|
5406
|
-
zz2[i2] = _zz[i];
|
|
5407
|
-
i2++;
|
|
5408
|
-
n2++;
|
|
5409
|
-
}
|
|
5410
|
-
}
|
|
5411
|
-
if (n2 == 1) {
|
|
5412
|
-
error("Collapsed arc");
|
|
5413
|
-
// This should not happen (endpoints should be z == Infinity)
|
|
5414
|
-
// Could handle like this, instead of throwing an error:
|
|
5415
|
-
// n2 = 0;
|
|
5416
|
-
// xx2.pop();
|
|
5417
|
-
// yy2.pop();
|
|
5418
|
-
// zz2.pop();
|
|
5419
|
-
}
|
|
5420
|
-
nn2[arcId] = n2;
|
|
5421
|
-
}
|
|
5422
|
-
return {
|
|
5423
|
-
xx: xx2,
|
|
5424
|
-
yy: yy2,
|
|
5425
|
-
zz: zz2,
|
|
5426
|
-
nn: nn2
|
|
5427
|
-
};
|
|
5449
|
+
return filterVertexData(getVertexData(), _zlimit);
|
|
5428
5450
|
}
|
|
5429
5451
|
|
|
5430
5452
|
this.getFilteredCopy = function() {
|
|
@@ -10823,28 +10845,59 @@
|
|
|
10823
10845
|
}
|
|
10824
10846
|
|
|
10825
10847
|
// gui: (optional) gui instance
|
|
10826
|
-
//
|
|
10848
|
+
// opts examples:
|
|
10849
|
+
// exporting from command line: { compact: true, file: 'tmp.msx', final: true }
|
|
10850
|
+
// exporting from gui export menu: {compact: true, format: 'msx'}
|
|
10851
|
+
// saving gui temp snapshot: {compact: false}
|
|
10827
10852
|
async function exportDatasetsToPack(datasets, opts) {
|
|
10828
10853
|
var obj = {
|
|
10829
10854
|
version: 1,
|
|
10830
10855
|
created: (new Date).toISOString(),
|
|
10831
|
-
datasets: await Promise.all(datasets.map(exportDataset))
|
|
10856
|
+
datasets: await Promise.all(datasets.map(dataset => exportDataset(dataset, opts)))
|
|
10832
10857
|
};
|
|
10833
|
-
if (opts.compact) {
|
|
10834
|
-
await applyCompression(obj);
|
|
10835
|
-
}
|
|
10836
10858
|
return obj;
|
|
10837
10859
|
}
|
|
10838
10860
|
|
|
10839
|
-
async function
|
|
10840
|
-
var
|
|
10841
|
-
|
|
10842
|
-
|
|
10861
|
+
async function exportDataset(dataset, opts) {
|
|
10862
|
+
var arcs = dataset.arcs;
|
|
10863
|
+
var arcData = null;
|
|
10864
|
+
if (arcs) {
|
|
10865
|
+
arcData = arcs.getVertexData();
|
|
10866
|
+
arcData.zlimit = arcs.getRetainedInterval(); // TODO: add this to getVertexData()
|
|
10867
|
+
arcData = await exportArcData(arcData, opts);
|
|
10868
|
+
}
|
|
10869
|
+
return {
|
|
10870
|
+
arcs: arcData,
|
|
10871
|
+
info: dataset.info ? exportInfo(dataset.info) : null,
|
|
10872
|
+
layers: await Promise.all((dataset.layers || []).map(exportLayer))
|
|
10873
|
+
};
|
|
10874
|
+
}
|
|
10875
|
+
|
|
10876
|
+
// compress unpacked + uncompressed snapshot data in-place
|
|
10877
|
+
async function compressSnapshotForExport(obj) {
|
|
10878
|
+
var promises = obj.datasets.map(d => {
|
|
10879
|
+
compressDatasetForExport(d);
|
|
10843
10880
|
});
|
|
10844
10881
|
await Promise.all(promises);
|
|
10882
|
+
return;
|
|
10845
10883
|
}
|
|
10846
10884
|
|
|
10847
|
-
async function
|
|
10885
|
+
async function compressDatasetForExport(obj) {
|
|
10886
|
+
if (!obj.arcs) return;
|
|
10887
|
+
var arcData = importArcData(obj.arcs); // convert buffers to typed arrays
|
|
10888
|
+
obj.arcs = await exportArcData(arcData, {compact: true}); // re-export to compressed buffers
|
|
10889
|
+
}
|
|
10890
|
+
|
|
10891
|
+
function flattenArcs(arcData) {
|
|
10892
|
+
if (arcData.zz && arcData.zlimit) {
|
|
10893
|
+
// replace unfiltered arc data with flattened arc data
|
|
10894
|
+
arcData = filterVertexData(arcData, arcData.zlimit);
|
|
10895
|
+
delete arcData.zz;
|
|
10896
|
+
}
|
|
10897
|
+
return arcData;
|
|
10898
|
+
}
|
|
10899
|
+
|
|
10900
|
+
async function gzipArcData(obj, opts) {
|
|
10848
10901
|
var gzipOpts = Object.assign({level: 1, consume: false}, opts);
|
|
10849
10902
|
var promises = [gzipAsync(obj.nn, gzipOpts), gzipAsync(obj.xx, gzipOpts), gzipAsync(obj.yy, gzipOpts)];
|
|
10850
10903
|
if (obj.zz) promises.push(gzipAsync(obj.zz, gzipOpts));
|
|
@@ -10855,27 +10908,36 @@
|
|
|
10855
10908
|
if (obj.zz) obj.zz = results.shift();
|
|
10856
10909
|
}
|
|
10857
10910
|
|
|
10858
|
-
|
|
10911
|
+
function importArcData(obj) {
|
|
10859
10912
|
return {
|
|
10860
|
-
|
|
10861
|
-
|
|
10862
|
-
|
|
10913
|
+
nn: new Uint32Array(obj.nn.buffer, 0, obj.nn.length / 4),
|
|
10914
|
+
xx: new Float64Array(obj.xx.buffer, 0, obj.xx.length / 8),
|
|
10915
|
+
yy: new Float64Array(obj.yy.buffer, 0, obj.yy.length / 8),
|
|
10916
|
+
zz: obj.zz ? new Float64Array(obj.zz.buffer, 0, obj.zz.length / 8) : null,
|
|
10917
|
+
zlimit: obj.zlimit || 0
|
|
10863
10918
|
};
|
|
10864
10919
|
}
|
|
10865
10920
|
|
|
10866
|
-
function
|
|
10867
|
-
|
|
10868
|
-
|
|
10869
|
-
|
|
10870
|
-
|
|
10871
|
-
var
|
|
10872
|
-
return {
|
|
10921
|
+
async function exportArcData(data, opts) {
|
|
10922
|
+
// TODO: consider removing arcs that are not referenced by any layer
|
|
10923
|
+
if (opts.compact && data.zz) {
|
|
10924
|
+
data = flattenArcs(data); // bake in any simplification
|
|
10925
|
+
}
|
|
10926
|
+
var output = {
|
|
10873
10927
|
nn: typedArrayToBuffer(data.nn),
|
|
10874
10928
|
xx: typedArrayToBuffer(data.xx),
|
|
10875
10929
|
yy: typedArrayToBuffer(data.yy),
|
|
10876
10930
|
zz: data.zz ? typedArrayToBuffer(data.zz) : null,
|
|
10877
|
-
zlimit:
|
|
10931
|
+
zlimit: data.zlimit || 0
|
|
10878
10932
|
};
|
|
10933
|
+
if (opts.compact && data.zz) {
|
|
10934
|
+
await gzipArcData(output);
|
|
10935
|
+
}
|
|
10936
|
+
return output;
|
|
10937
|
+
}
|
|
10938
|
+
|
|
10939
|
+
function typedArrayToBuffer(arr) {
|
|
10940
|
+
return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
10879
10941
|
}
|
|
10880
10942
|
|
|
10881
10943
|
async function exportLayer(lyr) {
|
|
@@ -10909,8 +10971,8 @@
|
|
|
10909
10971
|
exportPackedDatasets: exportPackedDatasets,
|
|
10910
10972
|
pack: pack,
|
|
10911
10973
|
exportDatasetsToPack: exportDatasetsToPack,
|
|
10912
|
-
applyCompression: applyCompression,
|
|
10913
10974
|
exportDataset: exportDataset,
|
|
10975
|
+
compressSnapshotForExport: compressSnapshotForExport,
|
|
10914
10976
|
exportInfo: exportInfo
|
|
10915
10977
|
});
|
|
10916
10978
|
|
|
@@ -12488,7 +12550,6 @@
|
|
|
12488
12550
|
return +n.toPrecision(d);
|
|
12489
12551
|
}
|
|
12490
12552
|
|
|
12491
|
-
|
|
12492
12553
|
function roundToDigits(n, d) {
|
|
12493
12554
|
return +n.toFixed(d); // string conversion makes this slow
|
|
12494
12555
|
}
|
|
@@ -12552,6 +12613,37 @@
|
|
|
12552
12613
|
});
|
|
12553
12614
|
}
|
|
12554
12615
|
|
|
12616
|
+
const fround2 = (function() {
|
|
12617
|
+
var arr = new Float32Array(1);
|
|
12618
|
+
return function(x) {
|
|
12619
|
+
arr[0] = x;
|
|
12620
|
+
return arr[0];
|
|
12621
|
+
};
|
|
12622
|
+
})();
|
|
12623
|
+
|
|
12624
|
+
// This function rounds towards 0 (i.e. floor). TODO: round properly
|
|
12625
|
+
// @bits: number of bits to round
|
|
12626
|
+
// performance: about 3x slower than Math.fround()
|
|
12627
|
+
function getBinaryRoundingFunction(bits) {
|
|
12628
|
+
// double: sign (1) exponent (11) fraction (52)
|
|
12629
|
+
// single: sign (1) exponent (8) fraction (23)
|
|
12630
|
+
if ((bits >= 1 && bits <= 32) === false) {
|
|
12631
|
+
error('Invalid bits argument:', bits);
|
|
12632
|
+
}
|
|
12633
|
+
var isLE = require('os').endianness() == 'LE';
|
|
12634
|
+
var fp = new Float64Array(1);
|
|
12635
|
+
var leastBits = new Uint32Array(fp.buffer, isLE ? 0 : 4, 1);
|
|
12636
|
+
var mask = 2 ** 32 - 2 ** bits; // e.g. bits = 4 -> 0b11110000
|
|
12637
|
+
return function(x) {
|
|
12638
|
+
fp[0] = x;
|
|
12639
|
+
leastBits[0] = leastBits[0] & mask;
|
|
12640
|
+
return fp[0];
|
|
12641
|
+
};
|
|
12642
|
+
}
|
|
12643
|
+
|
|
12644
|
+
// "round to even" on the 23rd bit of the mantissa
|
|
12645
|
+
const fround = Math.fround || fround2;
|
|
12646
|
+
|
|
12555
12647
|
function setCoordinatePrecision(dataset, precision) {
|
|
12556
12648
|
var round = getRoundingFunction(precision);
|
|
12557
12649
|
// var dissolvePolygon, nodes;
|
|
@@ -12586,6 +12678,9 @@
|
|
|
12586
12678
|
getRoundedCoordString: getRoundedCoordString,
|
|
12587
12679
|
getRoundedCoords: getRoundedCoords,
|
|
12588
12680
|
roundPoints: roundPoints,
|
|
12681
|
+
fround2: fround2,
|
|
12682
|
+
getBinaryRoundingFunction: getBinaryRoundingFunction,
|
|
12683
|
+
fround: fround,
|
|
12589
12684
|
setCoordinatePrecision: setCoordinatePrecision
|
|
12590
12685
|
});
|
|
12591
12686
|
|
|
@@ -15914,6 +16009,67 @@
|
|
|
15914
16009
|
formatIntersectingSegment: formatIntersectingSegment
|
|
15915
16010
|
});
|
|
15916
16011
|
|
|
16012
|
+
// Remap any references to duplicate arcs in paths to use the same arcs
|
|
16013
|
+
// Remove any unused arcs from the dataset's ArcCollection.
|
|
16014
|
+
// Return a NodeCollection
|
|
16015
|
+
function cleanArcReferences(dataset) {
|
|
16016
|
+
var nodes = new NodeCollection(dataset.arcs);
|
|
16017
|
+
var map = findDuplicateArcs(nodes);
|
|
16018
|
+
var dropCount;
|
|
16019
|
+
if (map) {
|
|
16020
|
+
replaceIndexedArcIds(dataset, map);
|
|
16021
|
+
}
|
|
16022
|
+
dropCount = deleteUnusedArcs(dataset);
|
|
16023
|
+
if (dropCount > 0) {
|
|
16024
|
+
// rebuild nodes if arcs have changed
|
|
16025
|
+
nodes = new NodeCollection(dataset.arcs);
|
|
16026
|
+
}
|
|
16027
|
+
return nodes;
|
|
16028
|
+
}
|
|
16029
|
+
|
|
16030
|
+
function deleteUnusedArcs(dataset) {
|
|
16031
|
+
var test = getArcPresenceTest2(dataset.layers, dataset.arcs);
|
|
16032
|
+
var count1 = dataset.arcs.size();
|
|
16033
|
+
var map = dataset.arcs.deleteArcs(test); // condenses arcs
|
|
16034
|
+
var count2 = dataset.arcs.size();
|
|
16035
|
+
var deleteCount = count1 - count2;
|
|
16036
|
+
if (deleteCount > 0) {
|
|
16037
|
+
replaceIndexedArcIds(dataset, map);
|
|
16038
|
+
}
|
|
16039
|
+
return deleteCount;
|
|
16040
|
+
}
|
|
16041
|
+
|
|
16042
|
+
// @map an Object mapping old to new ids
|
|
16043
|
+
function replaceIndexedArcIds(dataset, map) {
|
|
16044
|
+
var remapPath = function(ids) {
|
|
16045
|
+
var arcId, absId, id2;
|
|
16046
|
+
for (var i=0; i<ids.length; i++) {
|
|
16047
|
+
arcId = ids[i];
|
|
16048
|
+
absId = absArcId(arcId);
|
|
16049
|
+
id2 = map[absId];
|
|
16050
|
+
ids[i] = arcId == absId ? id2 : ~id2;
|
|
16051
|
+
}
|
|
16052
|
+
return ids;
|
|
16053
|
+
};
|
|
16054
|
+
dataset.layers.forEach(function(lyr) {
|
|
16055
|
+
if (layerHasPaths(lyr)) {
|
|
16056
|
+
editShapes(lyr.shapes, remapPath);
|
|
16057
|
+
}
|
|
16058
|
+
});
|
|
16059
|
+
}
|
|
16060
|
+
|
|
16061
|
+
function findDuplicateArcs(nodes) {
|
|
16062
|
+
var map = new Int32Array(nodes.arcs.size()),
|
|
16063
|
+
count = 0,
|
|
16064
|
+
i2;
|
|
16065
|
+
for (var i=0, n=nodes.arcs.size(); i<n; i++) {
|
|
16066
|
+
i2 = nodes.findDuplicateArc(i);
|
|
16067
|
+
map[i] = i2;
|
|
16068
|
+
if (i != i2) count++;
|
|
16069
|
+
}
|
|
16070
|
+
return count > 0 ? map : null;
|
|
16071
|
+
}
|
|
16072
|
+
|
|
15917
16073
|
// Functions for dividing polygons and polygons at points where arc-segments intersect
|
|
15918
16074
|
|
|
15919
16075
|
// TODO:
|
|
@@ -16003,68 +16159,6 @@
|
|
|
16003
16159
|
}
|
|
16004
16160
|
|
|
16005
16161
|
|
|
16006
|
-
// Remap any references to duplicate arcs in paths to use the same arcs
|
|
16007
|
-
// Remove any unused arcs from the dataset's ArcCollection.
|
|
16008
|
-
// Return a NodeCollection
|
|
16009
|
-
function cleanArcReferences(dataset) {
|
|
16010
|
-
var nodes = new NodeCollection(dataset.arcs);
|
|
16011
|
-
var map = findDuplicateArcs(nodes);
|
|
16012
|
-
var dropCount;
|
|
16013
|
-
if (map) {
|
|
16014
|
-
replaceIndexedArcIds(dataset, map);
|
|
16015
|
-
}
|
|
16016
|
-
dropCount = deleteUnusedArcs(dataset);
|
|
16017
|
-
if (dropCount > 0) {
|
|
16018
|
-
// rebuild nodes if arcs have changed
|
|
16019
|
-
nodes = new NodeCollection(dataset.arcs);
|
|
16020
|
-
}
|
|
16021
|
-
return nodes;
|
|
16022
|
-
}
|
|
16023
|
-
|
|
16024
|
-
|
|
16025
|
-
// @map an Object mapping old to new ids
|
|
16026
|
-
function replaceIndexedArcIds(dataset, map) {
|
|
16027
|
-
var remapPath = function(ids) {
|
|
16028
|
-
var arcId, absId, id2;
|
|
16029
|
-
for (var i=0; i<ids.length; i++) {
|
|
16030
|
-
arcId = ids[i];
|
|
16031
|
-
absId = absArcId(arcId);
|
|
16032
|
-
id2 = map[absId];
|
|
16033
|
-
ids[i] = arcId == absId ? id2 : ~id2;
|
|
16034
|
-
}
|
|
16035
|
-
return ids;
|
|
16036
|
-
};
|
|
16037
|
-
dataset.layers.forEach(function(lyr) {
|
|
16038
|
-
if (layerHasPaths(lyr)) {
|
|
16039
|
-
editShapes(lyr.shapes, remapPath);
|
|
16040
|
-
}
|
|
16041
|
-
});
|
|
16042
|
-
}
|
|
16043
|
-
|
|
16044
|
-
function findDuplicateArcs(nodes) {
|
|
16045
|
-
var map = new Int32Array(nodes.arcs.size()),
|
|
16046
|
-
count = 0,
|
|
16047
|
-
i2;
|
|
16048
|
-
for (var i=0, n=nodes.arcs.size(); i<n; i++) {
|
|
16049
|
-
i2 = nodes.findDuplicateArc(i);
|
|
16050
|
-
map[i] = i2;
|
|
16051
|
-
if (i != i2) count++;
|
|
16052
|
-
}
|
|
16053
|
-
return count > 0 ? map : null;
|
|
16054
|
-
}
|
|
16055
|
-
|
|
16056
|
-
function deleteUnusedArcs(dataset) {
|
|
16057
|
-
var test = getArcPresenceTest2(dataset.layers, dataset.arcs);
|
|
16058
|
-
var count1 = dataset.arcs.size();
|
|
16059
|
-
var map = dataset.arcs.deleteArcs(test); // condenses arcs
|
|
16060
|
-
var count2 = dataset.arcs.size();
|
|
16061
|
-
var deleteCount = count1 - count2;
|
|
16062
|
-
if (deleteCount > 0) {
|
|
16063
|
-
replaceIndexedArcIds(dataset, map);
|
|
16064
|
-
}
|
|
16065
|
-
return deleteCount;
|
|
16066
|
-
}
|
|
16067
|
-
|
|
16068
16162
|
// Return a function for updating a path (array of arc ids)
|
|
16069
16163
|
// @map array generated by insertCutPoints()
|
|
16070
16164
|
// @arcCount number of arcs in divided collection (kludge)
|
|
@@ -16458,7 +16552,8 @@
|
|
|
16458
16552
|
if (id >= 0 && id < n) {
|
|
16459
16553
|
return index[id] - 1;
|
|
16460
16554
|
} else {
|
|
16461
|
-
|
|
16555
|
+
return -1;
|
|
16556
|
+
// error('Invalid index');
|
|
16462
16557
|
}
|
|
16463
16558
|
};
|
|
16464
16559
|
}
|
|
@@ -17419,8 +17514,9 @@
|
|
|
17419
17514
|
exporter = GeoJSON.exporters[lyr.geometry_type],
|
|
17420
17515
|
geom = shape ? exporter(shape, dataset.arcs, opts) : null,
|
|
17421
17516
|
obj = null;
|
|
17517
|
+
|
|
17422
17518
|
if (asFeatures) {
|
|
17423
|
-
obj =
|
|
17519
|
+
obj = composeFeature(geom, properties ? properties[i] : null, opts);
|
|
17424
17520
|
if (ids) {
|
|
17425
17521
|
obj.id = ids[i];
|
|
17426
17522
|
}
|
|
@@ -17444,6 +17540,20 @@
|
|
|
17444
17540
|
}, []);
|
|
17445
17541
|
}
|
|
17446
17542
|
|
|
17543
|
+
function composeFeature(geom, properties, opts) {
|
|
17544
|
+
var feat = GeoJSON.toFeature(geom, properties);
|
|
17545
|
+
if (Array.isArray(opts.hoist) && properties) {
|
|
17546
|
+
// don't modify properties of source feature
|
|
17547
|
+
feat.properties = Object.assign({}, properties);
|
|
17548
|
+
opts.hoist.forEach(field => {
|
|
17549
|
+
if (properties.hasOwnProperty(field)) {
|
|
17550
|
+
feat[field] = properties[field];
|
|
17551
|
+
delete feat.properties[field];
|
|
17552
|
+
}
|
|
17553
|
+
});
|
|
17554
|
+
}
|
|
17555
|
+
return feat;
|
|
17556
|
+
}
|
|
17447
17557
|
|
|
17448
17558
|
function getRFC7946Warnings(dataset) {
|
|
17449
17559
|
var P = getDatasetCRS(dataset);
|
|
@@ -18412,7 +18522,8 @@
|
|
|
18412
18522
|
// null values indicate the lack of a function for parsing/identifying this property
|
|
18413
18523
|
// (in which case a heuristic is used for distinguishing a string literal from an expression)
|
|
18414
18524
|
var stylePropertyTypes = {
|
|
18415
|
-
css: null,
|
|
18525
|
+
// css: null,
|
|
18526
|
+
css: 'inlinecss',
|
|
18416
18527
|
class: 'classname',
|
|
18417
18528
|
dx: 'measure',
|
|
18418
18529
|
dy: 'measure',
|
|
@@ -18599,6 +18710,8 @@
|
|
|
18599
18710
|
val = isPattern(strVal) ? strVal : null;
|
|
18600
18711
|
} else if (type == 'boolean') {
|
|
18601
18712
|
val = parseBoolean(strVal);
|
|
18713
|
+
} else if (type == 'inlinecss') {
|
|
18714
|
+
val = strVal; // TODO: validate
|
|
18602
18715
|
}
|
|
18603
18716
|
// else {
|
|
18604
18717
|
// // unknown type -- assume literal value
|
|
@@ -21534,6 +21647,14 @@ ${svg}
|
|
|
21534
21647
|
}
|
|
21535
21648
|
return memo.concat(exportFileContent(dataset, opts));
|
|
21536
21649
|
}, []);
|
|
21650
|
+
|
|
21651
|
+
if (opts.bbox_index) {
|
|
21652
|
+
// If rounding or quantization are applied during export, bounds may
|
|
21653
|
+
// change somewhat... consider adding a bounds property to each layer during
|
|
21654
|
+
// export when appropriate.
|
|
21655
|
+
files.push(createIndexFile(datasets));
|
|
21656
|
+
}
|
|
21657
|
+
|
|
21537
21658
|
// need unique names for multiple output files
|
|
21538
21659
|
assignUniqueFileNames(files);
|
|
21539
21660
|
|
|
@@ -21591,15 +21712,7 @@ ${svg}
|
|
|
21591
21712
|
}
|
|
21592
21713
|
|
|
21593
21714
|
validateLayerData(dataset.layers);
|
|
21594
|
-
|
|
21595
21715
|
files = exporter(dataset, opts).concat(files);
|
|
21596
|
-
// If rounding or quantization are applied during export, bounds may
|
|
21597
|
-
// change somewhat... consider adding a bounds property to each layer during
|
|
21598
|
-
// export when appropriate.
|
|
21599
|
-
if (opts.bbox_index) {
|
|
21600
|
-
files.push(createIndexFile(dataset));
|
|
21601
|
-
}
|
|
21602
|
-
|
|
21603
21716
|
validateFileNames(files);
|
|
21604
21717
|
return files;
|
|
21605
21718
|
}
|
|
@@ -21620,13 +21733,16 @@ ${svg}
|
|
|
21620
21733
|
// Generate json file with bounding boxes and names of each export layer
|
|
21621
21734
|
// TODO: consider making this a command, or at least make format settable
|
|
21622
21735
|
//
|
|
21623
|
-
function createIndexFile(
|
|
21624
|
-
var index =
|
|
21625
|
-
|
|
21626
|
-
|
|
21627
|
-
|
|
21628
|
-
|
|
21629
|
-
|
|
21736
|
+
function createIndexFile(datasets) {
|
|
21737
|
+
var index = [];
|
|
21738
|
+
datasets.forEach(function(dataset) {
|
|
21739
|
+
dataset.layers.forEach(function(lyr) {
|
|
21740
|
+
var bounds = getLayerBounds(lyr, dataset.arcs);
|
|
21741
|
+
index.push({
|
|
21742
|
+
bbox: bounds.toArray(),
|
|
21743
|
+
name: lyr.name
|
|
21744
|
+
});
|
|
21745
|
+
});
|
|
21630
21746
|
});
|
|
21631
21747
|
|
|
21632
21748
|
return {
|
|
@@ -23349,7 +23465,7 @@ ${svg}
|
|
|
23349
23465
|
.option('string-fields', stringFieldsOpt)
|
|
23350
23466
|
.option('field-types', fieldTypesOpt)
|
|
23351
23467
|
.option('name', {
|
|
23352
|
-
describe: '
|
|
23468
|
+
describe: 'rename the imported layer(s)'
|
|
23353
23469
|
})
|
|
23354
23470
|
.option('geometry-type', {
|
|
23355
23471
|
// undocumented; GeoJSON import rejects all but one kind of geometry
|
|
@@ -23518,6 +23634,10 @@ ${svg}
|
|
|
23518
23634
|
describe: '[GeoJSON/JSON] output newline-delimited features or records',
|
|
23519
23635
|
type: 'flag'
|
|
23520
23636
|
})
|
|
23637
|
+
.option('hoist', {
|
|
23638
|
+
describe: '[GeoJSON] move properties to the root level of each Feature',
|
|
23639
|
+
type: 'strings'
|
|
23640
|
+
})
|
|
23521
23641
|
.option('width', {
|
|
23522
23642
|
describe: '[SVG/TopoJSON] pixel width of output (SVG default is 800)',
|
|
23523
23643
|
type: 'number'
|
|
@@ -24696,9 +24816,9 @@ ${svg}
|
|
|
24696
24816
|
.option('class', {
|
|
24697
24817
|
describe: 'name of CSS class or classes (space-separated)'
|
|
24698
24818
|
})
|
|
24699
|
-
|
|
24700
|
-
|
|
24701
|
-
|
|
24819
|
+
.option('css', {
|
|
24820
|
+
describe: 'inline css style'
|
|
24821
|
+
})
|
|
24702
24822
|
.option('fill', {
|
|
24703
24823
|
describe: 'fill color; examples: #eee pink rgba(0, 0, 0, 0.2)'
|
|
24704
24824
|
})
|
|
@@ -33468,7 +33588,6 @@ ${svg}
|
|
|
33468
33588
|
stop('Missing a data field to classify');
|
|
33469
33589
|
}
|
|
33470
33590
|
|
|
33471
|
-
|
|
33472
33591
|
// get the number of classes and the number of values
|
|
33473
33592
|
//
|
|
33474
33593
|
// expand categories if value is '*'
|
|
@@ -41274,21 +41393,24 @@ ${svg}
|
|
|
41274
41393
|
parseConsoleCommands: parseConsoleCommands
|
|
41275
41394
|
});
|
|
41276
41395
|
|
|
41277
|
-
cmd.run = function(job, targets, opts
|
|
41396
|
+
cmd.run = async function(job, targets, opts) {
|
|
41278
41397
|
var commandStr, commands;
|
|
41279
41398
|
if (!opts.expression) {
|
|
41280
41399
|
stop("Missing expression parameter");
|
|
41281
41400
|
}
|
|
41282
41401
|
commandStr = runGlobalExpression(opts.expression, targets);
|
|
41402
|
+
// Support async functions as expressions
|
|
41403
|
+
if (utils.isPromise(commandStr)) {
|
|
41404
|
+
commandStr = await commandStr;
|
|
41405
|
+
}
|
|
41283
41406
|
if (commandStr) {
|
|
41284
41407
|
message(`command: [${commandStr}]`);
|
|
41285
41408
|
commands = parseCommands(commandStr);
|
|
41286
|
-
runParsedCommands(commands, job
|
|
41287
|
-
} else {
|
|
41288
|
-
cb(null);
|
|
41409
|
+
await utils.promisify(runParsedCommands)(commands, job);
|
|
41289
41410
|
}
|
|
41290
41411
|
};
|
|
41291
41412
|
|
|
41413
|
+
// This could return a Promise or a value or nothing
|
|
41292
41414
|
function runGlobalExpression(expression, targets) {
|
|
41293
41415
|
var ctx = getBaseContext();
|
|
41294
41416
|
var output, targetData;
|
|
@@ -42415,6 +42537,7 @@ ${svg}
|
|
|
42415
42537
|
shapes = lyr0.shapes,
|
|
42416
42538
|
index = {},
|
|
42417
42539
|
splitLayers = [],
|
|
42540
|
+
n = getFeatureCount(lyr0),
|
|
42418
42541
|
namer;
|
|
42419
42542
|
|
|
42420
42543
|
if (opts.ids) {
|
|
@@ -42423,11 +42546,18 @@ ${svg}
|
|
|
42423
42546
|
namer = getSplitNameFunction(lyr0, expression);
|
|
42424
42547
|
}
|
|
42425
42548
|
|
|
42549
|
+
// // halt if split field is missing
|
|
42426
42550
|
// if (splitField) {
|
|
42427
42551
|
// internal.requireDataField(lyr0, splitField);
|
|
42428
42552
|
// }
|
|
42429
42553
|
|
|
42430
|
-
|
|
42554
|
+
// if input layer is empty, return original layer
|
|
42555
|
+
// TODO: consider halting
|
|
42556
|
+
if (n === 0) {
|
|
42557
|
+
return [lyr0];
|
|
42558
|
+
}
|
|
42559
|
+
|
|
42560
|
+
utils.repeat(n, function(i) {
|
|
42431
42561
|
var name = namer(i),
|
|
42432
42562
|
lyr;
|
|
42433
42563
|
|
|
@@ -42450,6 +42580,7 @@ ${svg}
|
|
|
42450
42580
|
lyr.data.getRecords().push(properties[i]);
|
|
42451
42581
|
}
|
|
42452
42582
|
});
|
|
42583
|
+
|
|
42453
42584
|
return splitLayers;
|
|
42454
42585
|
};
|
|
42455
42586
|
|
|
@@ -42460,26 +42591,34 @@ ${svg}
|
|
|
42460
42591
|
};
|
|
42461
42592
|
}
|
|
42462
42593
|
|
|
42463
|
-
function
|
|
42464
|
-
// if not splitting on an expression and layer is unnamed, name split-apart layers
|
|
42465
|
-
// like: split-1, split-2, ...
|
|
42466
|
-
return function(i) {
|
|
42467
|
-
return (lyr && lyr.name || 'split') + '-' + (i + 1);
|
|
42468
|
-
};
|
|
42469
|
-
}
|
|
42470
|
-
|
|
42471
|
-
function getSplitNameFunction(lyr, exp) {
|
|
42594
|
+
function getSplitNameFunction(lyr, arg) {
|
|
42472
42595
|
var compiled;
|
|
42473
|
-
if (!
|
|
42596
|
+
if (!arg) {
|
|
42597
|
+
// if not splitting on an expression and layer is unnamed, name split-apart layers
|
|
42598
|
+
// like: split-1, split-2, ...
|
|
42599
|
+
return function(i) {
|
|
42600
|
+
return (lyr && lyr.name || 'split') + '-' + (i + 1);
|
|
42601
|
+
};
|
|
42602
|
+
}
|
|
42603
|
+
if (lyr.data && lyr.data.fieldExists(arg)) {
|
|
42604
|
+
// Argument is a field name
|
|
42605
|
+
return function(i) {
|
|
42606
|
+
var rec = lyr.data.getRecords()[i];
|
|
42607
|
+
return rec ? valueToLayerName(rec[arg]) : '';
|
|
42608
|
+
};
|
|
42609
|
+
}
|
|
42610
|
+
// Assume: argument is an expression
|
|
42474
42611
|
lyr = {name: lyr.name, data: lyr.data}; // remove shape info
|
|
42475
|
-
compiled = compileValueExpression(
|
|
42612
|
+
compiled = compileValueExpression(arg, lyr, null);
|
|
42476
42613
|
return function(i) {
|
|
42477
42614
|
var val = compiled(i);
|
|
42478
|
-
return
|
|
42479
|
-
// return val || val === 0 ? String(val) : '';
|
|
42615
|
+
return valueToLayerName(val);
|
|
42480
42616
|
};
|
|
42481
42617
|
}
|
|
42482
42618
|
|
|
42619
|
+
function valueToLayerName(val) {
|
|
42620
|
+
return String(val);
|
|
42621
|
+
}
|
|
42483
42622
|
|
|
42484
42623
|
// internal.getSplitKey = function(i, field, properties) {
|
|
42485
42624
|
// var rec = field && properties ? properties[i] : null;
|
|
@@ -42515,6 +42654,9 @@ ${svg}
|
|
|
42515
42654
|
|
|
42516
42655
|
cmd.svgStyle = function(lyr, dataset, opts) {
|
|
42517
42656
|
var filter;
|
|
42657
|
+
if (getFeatureCount(lyr) === 0) {
|
|
42658
|
+
return;
|
|
42659
|
+
}
|
|
42518
42660
|
if (!lyr.data) {
|
|
42519
42661
|
initDataTable(lyr);
|
|
42520
42662
|
}
|
|
@@ -43820,7 +43962,7 @@ ${svg}
|
|
|
43820
43962
|
});
|
|
43821
43963
|
|
|
43822
43964
|
} else if (name == 'run') {
|
|
43823
|
-
await
|
|
43965
|
+
await cmd.run(job, targets, opts);
|
|
43824
43966
|
|
|
43825
43967
|
} else if (name == 'scalebar') {
|
|
43826
43968
|
cmd.scalebar(job.catalog, opts);
|
|
@@ -43843,7 +43985,7 @@ ${svg}
|
|
|
43843
43985
|
|
|
43844
43986
|
} else if (name == 'snap') {
|
|
43845
43987
|
// cmd.snap(targetDataset, opts);
|
|
43846
|
-
applyCommandToEachTarget(targets, opts);
|
|
43988
|
+
applyCommandToEachTarget(cmd.snap, targets, opts);
|
|
43847
43989
|
|
|
43848
43990
|
} else if (name == 'sort') {
|
|
43849
43991
|
applyCommandToEachLayer(cmd.sortFeatures, targetLayers, arcs, opts);
|
|
@@ -44097,6 +44239,13 @@ ${svg}
|
|
|
44097
44239
|
}
|
|
44098
44240
|
});
|
|
44099
44241
|
|
|
44242
|
+
var lastCmd = commands[commands.length - 1];
|
|
44243
|
+
if (!runningInBrowser() && lastCmd.name == 'o') {
|
|
44244
|
+
// in CLI, set 'final' flag on final -o command, so the export function knows
|
|
44245
|
+
// that it can modify the output dataset in-place instead of making a copy.
|
|
44246
|
+
lastCmd.options.final = true;
|
|
44247
|
+
}
|
|
44248
|
+
|
|
44100
44249
|
var batches = divideImportCommand(commands);
|
|
44101
44250
|
utils.reduceAsync(batches, null, nextGroup, done);
|
|
44102
44251
|
|
|
@@ -44165,11 +44314,6 @@ ${svg}
|
|
|
44165
44314
|
// @done: function([error], [job])
|
|
44166
44315
|
//
|
|
44167
44316
|
function runParsedCommands(commands, job, done) {
|
|
44168
|
-
if (!runningInBrowser() && commands[commands.length-1].name == 'o') {
|
|
44169
|
-
// in CLI, set 'final' flag on final -o command, so the export function knows
|
|
44170
|
-
// that it can modify the output dataset in-place instead of making a copy.
|
|
44171
|
-
commands[commands.length-1].options.final = true;
|
|
44172
|
-
}
|
|
44173
44317
|
if (!job) job = new Job();
|
|
44174
44318
|
commands = readAndRemoveSettings(job, commands);
|
|
44175
44319
|
if (!runningInBrowser()) {
|