mapshaper 0.6.44 → 0.6.46
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 +326 -178
- package/package.json +2 -2
- package/www/index.html +6 -6
- package/www/mapshaper-gui.js +204 -43
- package/www/mapshaper.js +326 -178
- package/www/page.css +25 -13
package/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.6.
|
|
3
|
+
var VERSION = "0.6.46";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -1813,6 +1813,23 @@
|
|
|
1813
1813
|
return [xmin, ymin, xmax, ymax];
|
|
1814
1814
|
}
|
|
1815
1815
|
|
|
1816
|
+
|
|
1817
|
+
function findArcIdFromVertexId(i, ii) {
|
|
1818
|
+
// binary search
|
|
1819
|
+
// possible optimization: use interpolation to find a better partition value.
|
|
1820
|
+
var lower = 0, upper = ii.length - 1;
|
|
1821
|
+
var middle;
|
|
1822
|
+
while (lower < upper) {
|
|
1823
|
+
middle = Math.ceil((lower + upper) / 2);
|
|
1824
|
+
if (i < ii[middle]) {
|
|
1825
|
+
upper = middle - 1;
|
|
1826
|
+
} else {
|
|
1827
|
+
lower = middle;
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
return lower; // assumes dataset is not empty
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1816
1833
|
function deleteVertex(arcs, i) {
|
|
1817
1834
|
var data = arcs.getVertexData();
|
|
1818
1835
|
var nn = data.nn;
|
|
@@ -1882,12 +1899,68 @@
|
|
|
1882
1899
|
arcs.updateVertexData(nn, xx2, yy2, zz2);
|
|
1883
1900
|
}
|
|
1884
1901
|
|
|
1902
|
+
function countFilteredVertices(zz, zlimit) {
|
|
1903
|
+
var count = 0;
|
|
1904
|
+
for (var i=0, n = zz.length; i<n; i++) {
|
|
1905
|
+
if (zz[i] >= zlimit) count++;
|
|
1906
|
+
}
|
|
1907
|
+
return count;
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
function filterVertexData(o, zlimit) {
|
|
1911
|
+
if (!o.zz) error('Expected simplification data');
|
|
1912
|
+
var xx = o.xx,
|
|
1913
|
+
yy = o.yy,
|
|
1914
|
+
zz = o.zz,
|
|
1915
|
+
len2 = countFilteredVertices(zz, zlimit),
|
|
1916
|
+
arcCount = o.nn.length,
|
|
1917
|
+
xx2 = new Float64Array(len2),
|
|
1918
|
+
yy2 = new Float64Array(len2),
|
|
1919
|
+
zz2 = new Float64Array(len2),
|
|
1920
|
+
nn2 = new Int32Array(arcCount),
|
|
1921
|
+
i = 0, i2 = 0,
|
|
1922
|
+
n, n2;
|
|
1923
|
+
|
|
1924
|
+
for (var arcId=0; arcId < arcCount; arcId++) {
|
|
1925
|
+
n2 = 0;
|
|
1926
|
+
n = o.nn[arcId];
|
|
1927
|
+
for (var end = i+n; i < end; i++) {
|
|
1928
|
+
if (zz[i] >= zlimit) {
|
|
1929
|
+
xx2[i2] = xx[i];
|
|
1930
|
+
yy2[i2] = yy[i];
|
|
1931
|
+
zz2[i2] = zz[i];
|
|
1932
|
+
i2++;
|
|
1933
|
+
n2++;
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
if (n2 == 1) {
|
|
1937
|
+
error("Collapsed arc");
|
|
1938
|
+
// This should not happen (endpoints should be z == Infinity)
|
|
1939
|
+
// Could handle like this, instead of throwing an error:
|
|
1940
|
+
// n2 = 0;
|
|
1941
|
+
// xx2.pop();
|
|
1942
|
+
// yy2.pop();
|
|
1943
|
+
// zz2.pop();
|
|
1944
|
+
}
|
|
1945
|
+
nn2[arcId] = n2;
|
|
1946
|
+
}
|
|
1947
|
+
return {
|
|
1948
|
+
xx: xx2,
|
|
1949
|
+
yy: yy2,
|
|
1950
|
+
zz: zz2,
|
|
1951
|
+
nn: nn2
|
|
1952
|
+
};
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1885
1955
|
var ArcUtils = /*#__PURE__*/Object.freeze({
|
|
1886
1956
|
__proto__: null,
|
|
1887
1957
|
absArcId: absArcId,
|
|
1888
1958
|
calcArcBounds: calcArcBounds,
|
|
1959
|
+
findArcIdFromVertexId: findArcIdFromVertexId,
|
|
1889
1960
|
deleteVertex: deleteVertex,
|
|
1890
|
-
insertVertex: insertVertex
|
|
1961
|
+
insertVertex: insertVertex,
|
|
1962
|
+
countFilteredVertices: countFilteredVertices,
|
|
1963
|
+
filterVertexData: filterVertexData
|
|
1891
1964
|
});
|
|
1892
1965
|
|
|
1893
1966
|
var WGS84 = {
|
|
@@ -3350,7 +3423,7 @@
|
|
|
3350
3423
|
var item;
|
|
3351
3424
|
for (var i=0; i<arr.length; i++) {
|
|
3352
3425
|
item = arr[i];
|
|
3353
|
-
if (item
|
|
3426
|
+
if (Array.isArray(item)) {
|
|
3354
3427
|
forEachArcId(item, cb);
|
|
3355
3428
|
} else if (utils.isInteger(item)) {
|
|
3356
3429
|
var val = cb(item);
|
|
@@ -5359,17 +5432,6 @@
|
|
|
5359
5432
|
initZData(zz || null);
|
|
5360
5433
|
};
|
|
5361
5434
|
|
|
5362
|
-
// Give access to raw data arrays...
|
|
5363
|
-
this.getVertexData = function() {
|
|
5364
|
-
return {
|
|
5365
|
-
xx: _xx,
|
|
5366
|
-
yy: _yy,
|
|
5367
|
-
zz: _zz,
|
|
5368
|
-
bb: _bb,
|
|
5369
|
-
nn: _nn,
|
|
5370
|
-
ii: _ii
|
|
5371
|
-
};
|
|
5372
|
-
};
|
|
5373
5435
|
|
|
5374
5436
|
this.getCopy = function() {
|
|
5375
5437
|
var copy = new ArcCollection(new Int32Array(_nn), new Float64Array(_xx),
|
|
@@ -5381,55 +5443,28 @@
|
|
|
5381
5443
|
return copy;
|
|
5382
5444
|
};
|
|
5383
5445
|
|
|
5446
|
+
|
|
5447
|
+
// Give access to raw data arrays...
|
|
5448
|
+
this.getVertexData = getVertexData;
|
|
5449
|
+
|
|
5450
|
+
function getVertexData() {
|
|
5451
|
+
return {
|
|
5452
|
+
xx: _xx,
|
|
5453
|
+
yy: _yy,
|
|
5454
|
+
zz: _zz,
|
|
5455
|
+
bb: _bb,
|
|
5456
|
+
nn: _nn,
|
|
5457
|
+
ii: _ii
|
|
5458
|
+
};
|
|
5459
|
+
}
|
|
5460
|
+
|
|
5384
5461
|
function getFilteredPointCount() {
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
var count = 0;
|
|
5388
|
-
for (var i=0, n = zz.length; i<n; i++) {
|
|
5389
|
-
if (zz[i] >= z) count++;
|
|
5390
|
-
}
|
|
5391
|
-
return count;
|
|
5462
|
+
if (!_zz || !_zlimit) return this.getPointCount();
|
|
5463
|
+
return countFilteredVertices(_zz, _zlimit);
|
|
5392
5464
|
}
|
|
5393
5465
|
|
|
5394
5466
|
function getFilteredVertexData() {
|
|
5395
|
-
|
|
5396
|
-
var arcCount = _nn.length;
|
|
5397
|
-
var xx2 = new Float64Array(len2),
|
|
5398
|
-
yy2 = new Float64Array(len2),
|
|
5399
|
-
zz2 = new Float64Array(len2),
|
|
5400
|
-
nn2 = new Int32Array(arcCount),
|
|
5401
|
-
i=0, i2 = 0,
|
|
5402
|
-
n, n2;
|
|
5403
|
-
|
|
5404
|
-
for (var arcId=0; arcId < arcCount; arcId++) {
|
|
5405
|
-
n2 = 0;
|
|
5406
|
-
n = _nn[arcId];
|
|
5407
|
-
for (var end = i+n; i < end; i++) {
|
|
5408
|
-
if (_zz[i] >= _zlimit) {
|
|
5409
|
-
xx2[i2] = _xx[i];
|
|
5410
|
-
yy2[i2] = _yy[i];
|
|
5411
|
-
zz2[i2] = _zz[i];
|
|
5412
|
-
i2++;
|
|
5413
|
-
n2++;
|
|
5414
|
-
}
|
|
5415
|
-
}
|
|
5416
|
-
if (n2 == 1) {
|
|
5417
|
-
error("Collapsed arc");
|
|
5418
|
-
// This should not happen (endpoints should be z == Infinity)
|
|
5419
|
-
// Could handle like this, instead of throwing an error:
|
|
5420
|
-
// n2 = 0;
|
|
5421
|
-
// xx2.pop();
|
|
5422
|
-
// yy2.pop();
|
|
5423
|
-
// zz2.pop();
|
|
5424
|
-
}
|
|
5425
|
-
nn2[arcId] = n2;
|
|
5426
|
-
}
|
|
5427
|
-
return {
|
|
5428
|
-
xx: xx2,
|
|
5429
|
-
yy: yy2,
|
|
5430
|
-
zz: zz2,
|
|
5431
|
-
nn: nn2
|
|
5432
|
-
};
|
|
5467
|
+
return filterVertexData(getVertexData(), _zlimit);
|
|
5433
5468
|
}
|
|
5434
5469
|
|
|
5435
5470
|
this.getFilteredCopy = function() {
|
|
@@ -6936,6 +6971,15 @@
|
|
|
6936
6971
|
utils.defaults(destInfo, srcInfo);
|
|
6937
6972
|
}
|
|
6938
6973
|
|
|
6974
|
+
function copyDatasetInfo(info) {
|
|
6975
|
+
// not a deep copy... objects like info.crs are read-only, so copy-by-reference
|
|
6976
|
+
// should be ok
|
|
6977
|
+
var info2 = Object.assign({}, info);
|
|
6978
|
+
if (Array.isArray(info.input_files)) {
|
|
6979
|
+
info2.input_files = info.input_files.concat();
|
|
6980
|
+
}
|
|
6981
|
+
return info2;
|
|
6982
|
+
}
|
|
6939
6983
|
|
|
6940
6984
|
function splitApartLayers(dataset, layers) {
|
|
6941
6985
|
var datasets = [];
|
|
@@ -7102,6 +7146,7 @@
|
|
|
7102
7146
|
__proto__: null,
|
|
7103
7147
|
splitDataset: splitDataset,
|
|
7104
7148
|
mergeDatasetInfo: mergeDatasetInfo,
|
|
7149
|
+
copyDatasetInfo: copyDatasetInfo,
|
|
7105
7150
|
splitApartLayers: splitApartLayers,
|
|
7106
7151
|
copyDataset: copyDataset,
|
|
7107
7152
|
copyDatasetForExport: copyDatasetForExport,
|
|
@@ -10828,28 +10873,59 @@
|
|
|
10828
10873
|
}
|
|
10829
10874
|
|
|
10830
10875
|
// gui: (optional) gui instance
|
|
10831
|
-
//
|
|
10876
|
+
// opts examples:
|
|
10877
|
+
// exporting from command line: { compact: true, file: 'tmp.msx', final: true }
|
|
10878
|
+
// exporting from gui export menu: {compact: true, format: 'msx'}
|
|
10879
|
+
// saving gui temp snapshot: {compact: false}
|
|
10832
10880
|
async function exportDatasetsToPack(datasets, opts) {
|
|
10833
10881
|
var obj = {
|
|
10834
10882
|
version: 1,
|
|
10835
10883
|
created: (new Date).toISOString(),
|
|
10836
|
-
datasets: await Promise.all(datasets.map(exportDataset))
|
|
10884
|
+
datasets: await Promise.all(datasets.map(dataset => exportDataset(dataset, opts)))
|
|
10837
10885
|
};
|
|
10838
|
-
if (opts.compact) {
|
|
10839
|
-
await applyCompression(obj);
|
|
10840
|
-
}
|
|
10841
10886
|
return obj;
|
|
10842
10887
|
}
|
|
10843
10888
|
|
|
10844
|
-
async function
|
|
10845
|
-
var
|
|
10846
|
-
|
|
10847
|
-
|
|
10889
|
+
async function exportDataset(dataset, opts) {
|
|
10890
|
+
var arcs = dataset.arcs;
|
|
10891
|
+
var arcData = null;
|
|
10892
|
+
if (arcs) {
|
|
10893
|
+
arcData = arcs.getVertexData();
|
|
10894
|
+
arcData.zlimit = arcs.getRetainedInterval(); // TODO: add this to getVertexData()
|
|
10895
|
+
arcData = await exportArcData(arcData, opts);
|
|
10896
|
+
}
|
|
10897
|
+
return {
|
|
10898
|
+
arcs: arcData,
|
|
10899
|
+
info: dataset.info ? exportInfo(dataset.info) : null,
|
|
10900
|
+
layers: await Promise.all((dataset.layers || []).map(exportLayer))
|
|
10901
|
+
};
|
|
10902
|
+
}
|
|
10903
|
+
|
|
10904
|
+
// compress unpacked + uncompressed snapshot data in-place
|
|
10905
|
+
async function compressSnapshotForExport(obj) {
|
|
10906
|
+
var promises = obj.datasets.map(d => {
|
|
10907
|
+
compressDatasetForExport(d);
|
|
10848
10908
|
});
|
|
10849
10909
|
await Promise.all(promises);
|
|
10910
|
+
return;
|
|
10911
|
+
}
|
|
10912
|
+
|
|
10913
|
+
async function compressDatasetForExport(obj) {
|
|
10914
|
+
if (!obj.arcs) return;
|
|
10915
|
+
var arcData = importArcData(obj.arcs); // convert buffers to typed arrays
|
|
10916
|
+
obj.arcs = await exportArcData(arcData, {compact: true}); // re-export to compressed buffers
|
|
10850
10917
|
}
|
|
10851
10918
|
|
|
10852
|
-
|
|
10919
|
+
function flattenArcs(arcData) {
|
|
10920
|
+
if (arcData.zz && arcData.zlimit) {
|
|
10921
|
+
// replace unfiltered arc data with flattened arc data
|
|
10922
|
+
arcData = filterVertexData(arcData, arcData.zlimit);
|
|
10923
|
+
delete arcData.zz;
|
|
10924
|
+
}
|
|
10925
|
+
return arcData;
|
|
10926
|
+
}
|
|
10927
|
+
|
|
10928
|
+
async function gzipArcData(obj, opts) {
|
|
10853
10929
|
var gzipOpts = Object.assign({level: 1, consume: false}, opts);
|
|
10854
10930
|
var promises = [gzipAsync(obj.nn, gzipOpts), gzipAsync(obj.xx, gzipOpts), gzipAsync(obj.yy, gzipOpts)];
|
|
10855
10931
|
if (obj.zz) promises.push(gzipAsync(obj.zz, gzipOpts));
|
|
@@ -10860,27 +10936,36 @@
|
|
|
10860
10936
|
if (obj.zz) obj.zz = results.shift();
|
|
10861
10937
|
}
|
|
10862
10938
|
|
|
10863
|
-
|
|
10939
|
+
function importArcData(obj) {
|
|
10864
10940
|
return {
|
|
10865
|
-
|
|
10866
|
-
|
|
10867
|
-
|
|
10941
|
+
nn: new Uint32Array(obj.nn.buffer, 0, obj.nn.length / 4),
|
|
10942
|
+
xx: new Float64Array(obj.xx.buffer, 0, obj.xx.length / 8),
|
|
10943
|
+
yy: new Float64Array(obj.yy.buffer, 0, obj.yy.length / 8),
|
|
10944
|
+
zz: obj.zz ? new Float64Array(obj.zz.buffer, 0, obj.zz.length / 8) : null,
|
|
10945
|
+
zlimit: obj.zlimit || 0
|
|
10868
10946
|
};
|
|
10869
10947
|
}
|
|
10870
10948
|
|
|
10871
|
-
function
|
|
10872
|
-
|
|
10873
|
-
|
|
10874
|
-
|
|
10875
|
-
|
|
10876
|
-
var
|
|
10877
|
-
return {
|
|
10949
|
+
async function exportArcData(data, opts) {
|
|
10950
|
+
// TODO: consider removing arcs that are not referenced by any layer
|
|
10951
|
+
if (opts.compact && data.zz) {
|
|
10952
|
+
data = flattenArcs(data); // bake in any simplification
|
|
10953
|
+
}
|
|
10954
|
+
var output = {
|
|
10878
10955
|
nn: typedArrayToBuffer(data.nn),
|
|
10879
10956
|
xx: typedArrayToBuffer(data.xx),
|
|
10880
10957
|
yy: typedArrayToBuffer(data.yy),
|
|
10881
10958
|
zz: data.zz ? typedArrayToBuffer(data.zz) : null,
|
|
10882
|
-
zlimit:
|
|
10959
|
+
zlimit: data.zlimit || 0
|
|
10883
10960
|
};
|
|
10961
|
+
if (opts.compact && data.zz) {
|
|
10962
|
+
await gzipArcData(output);
|
|
10963
|
+
}
|
|
10964
|
+
return output;
|
|
10965
|
+
}
|
|
10966
|
+
|
|
10967
|
+
function typedArrayToBuffer(arr) {
|
|
10968
|
+
return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
10884
10969
|
}
|
|
10885
10970
|
|
|
10886
10971
|
async function exportLayer(lyr) {
|
|
@@ -10914,8 +10999,8 @@
|
|
|
10914
10999
|
exportPackedDatasets: exportPackedDatasets,
|
|
10915
11000
|
pack: pack,
|
|
10916
11001
|
exportDatasetsToPack: exportDatasetsToPack,
|
|
10917
|
-
applyCompression: applyCompression,
|
|
10918
11002
|
exportDataset: exportDataset,
|
|
11003
|
+
compressSnapshotForExport: compressSnapshotForExport,
|
|
10919
11004
|
exportInfo: exportInfo
|
|
10920
11005
|
});
|
|
10921
11006
|
|
|
@@ -15424,6 +15509,17 @@
|
|
|
15424
15509
|
|
|
15425
15510
|
// Keep track of whether positive or negative integer ids are 'used' or not.
|
|
15426
15511
|
|
|
15512
|
+
|
|
15513
|
+
function SimpleIdTestIndex(n) {
|
|
15514
|
+
var index = new Uint8Array(n);
|
|
15515
|
+
this.setId = function(id) {
|
|
15516
|
+
index[id] = 1;
|
|
15517
|
+
};
|
|
15518
|
+
this.hasId = function(id) {
|
|
15519
|
+
return index[id] === 1;
|
|
15520
|
+
};
|
|
15521
|
+
}
|
|
15522
|
+
|
|
15427
15523
|
function IdTestIndex(n) {
|
|
15428
15524
|
var index = new Uint8Array(n);
|
|
15429
15525
|
var setList = [];
|
|
@@ -15686,15 +15782,30 @@
|
|
|
15686
15782
|
getHoleDivider: getHoleDivider
|
|
15687
15783
|
});
|
|
15688
15784
|
|
|
15689
|
-
// Convert an array of intersections into an ArcCollection (for display)
|
|
15690
|
-
//
|
|
15691
|
-
|
|
15692
15785
|
function getIntersectionPoints(intersections) {
|
|
15693
15786
|
return intersections.map(function(obj) {
|
|
15694
15787
|
return [obj.x, obj.y];
|
|
15695
15788
|
});
|
|
15696
15789
|
}
|
|
15697
15790
|
|
|
15791
|
+
function getIntersectionLayer(intersections, lyr, arcs) {
|
|
15792
|
+
// return {geometry_type: 'point', shapes: [getIntersectionPoints(XX)]};
|
|
15793
|
+
var ii = arcs.getVertexData().ii;
|
|
15794
|
+
var index = new SimpleIdTestIndex(arcs.size());
|
|
15795
|
+
forEachArcId(lyr.shapes, arcId => {
|
|
15796
|
+
index.setId(absArcId(arcId));
|
|
15797
|
+
});
|
|
15798
|
+
var points = [];
|
|
15799
|
+
intersections.forEach(obj => {
|
|
15800
|
+
var arc1 = findArcIdFromVertexId(obj.a[0], ii);
|
|
15801
|
+
var arc2 = findArcIdFromVertexId(obj.b[0], ii);
|
|
15802
|
+
if (index.hasId(arc1) && index.hasId(arc2)) {
|
|
15803
|
+
points.push([obj.x, obj.y]);
|
|
15804
|
+
}
|
|
15805
|
+
});
|
|
15806
|
+
return {geometry_type: 'point', shapes: [points]};
|
|
15807
|
+
}
|
|
15808
|
+
|
|
15698
15809
|
// Identify intersecting segments in an ArcCollection
|
|
15699
15810
|
//
|
|
15700
15811
|
// To find all intersections:
|
|
@@ -15942,6 +16053,7 @@
|
|
|
15942
16053
|
var SegmentIntersection = /*#__PURE__*/Object.freeze({
|
|
15943
16054
|
__proto__: null,
|
|
15944
16055
|
getIntersectionPoints: getIntersectionPoints,
|
|
16056
|
+
getIntersectionLayer: getIntersectionLayer,
|
|
15945
16057
|
findSegmentIntersections: findSegmentIntersections,
|
|
15946
16058
|
sortIntersections: sortIntersections,
|
|
15947
16059
|
dedupIntersections: dedupIntersections,
|
|
@@ -15952,6 +16064,67 @@
|
|
|
15952
16064
|
formatIntersectingSegment: formatIntersectingSegment
|
|
15953
16065
|
});
|
|
15954
16066
|
|
|
16067
|
+
// Remap any references to duplicate arcs in paths to use the same arcs
|
|
16068
|
+
// Remove any unused arcs from the dataset's ArcCollection.
|
|
16069
|
+
// Return a NodeCollection
|
|
16070
|
+
function cleanArcReferences(dataset) {
|
|
16071
|
+
var nodes = new NodeCollection(dataset.arcs);
|
|
16072
|
+
var map = findDuplicateArcs(nodes);
|
|
16073
|
+
var dropCount;
|
|
16074
|
+
if (map) {
|
|
16075
|
+
replaceIndexedArcIds(dataset, map);
|
|
16076
|
+
}
|
|
16077
|
+
dropCount = deleteUnusedArcs(dataset);
|
|
16078
|
+
if (dropCount > 0) {
|
|
16079
|
+
// rebuild nodes if arcs have changed
|
|
16080
|
+
nodes = new NodeCollection(dataset.arcs);
|
|
16081
|
+
}
|
|
16082
|
+
return nodes;
|
|
16083
|
+
}
|
|
16084
|
+
|
|
16085
|
+
function deleteUnusedArcs(dataset) {
|
|
16086
|
+
var test = getArcPresenceTest2(dataset.layers, dataset.arcs);
|
|
16087
|
+
var count1 = dataset.arcs.size();
|
|
16088
|
+
var map = dataset.arcs.deleteArcs(test); // condenses arcs
|
|
16089
|
+
var count2 = dataset.arcs.size();
|
|
16090
|
+
var deleteCount = count1 - count2;
|
|
16091
|
+
if (deleteCount > 0) {
|
|
16092
|
+
replaceIndexedArcIds(dataset, map);
|
|
16093
|
+
}
|
|
16094
|
+
return deleteCount;
|
|
16095
|
+
}
|
|
16096
|
+
|
|
16097
|
+
// @map an Object mapping old to new ids
|
|
16098
|
+
function replaceIndexedArcIds(dataset, map) {
|
|
16099
|
+
var remapPath = function(ids) {
|
|
16100
|
+
var arcId, absId, id2;
|
|
16101
|
+
for (var i=0; i<ids.length; i++) {
|
|
16102
|
+
arcId = ids[i];
|
|
16103
|
+
absId = absArcId(arcId);
|
|
16104
|
+
id2 = map[absId];
|
|
16105
|
+
ids[i] = arcId == absId ? id2 : ~id2;
|
|
16106
|
+
}
|
|
16107
|
+
return ids;
|
|
16108
|
+
};
|
|
16109
|
+
dataset.layers.forEach(function(lyr) {
|
|
16110
|
+
if (layerHasPaths(lyr)) {
|
|
16111
|
+
editShapes(lyr.shapes, remapPath);
|
|
16112
|
+
}
|
|
16113
|
+
});
|
|
16114
|
+
}
|
|
16115
|
+
|
|
16116
|
+
function findDuplicateArcs(nodes) {
|
|
16117
|
+
var map = new Int32Array(nodes.arcs.size()),
|
|
16118
|
+
count = 0,
|
|
16119
|
+
i2;
|
|
16120
|
+
for (var i=0, n=nodes.arcs.size(); i<n; i++) {
|
|
16121
|
+
i2 = nodes.findDuplicateArc(i);
|
|
16122
|
+
map[i] = i2;
|
|
16123
|
+
if (i != i2) count++;
|
|
16124
|
+
}
|
|
16125
|
+
return count > 0 ? map : null;
|
|
16126
|
+
}
|
|
16127
|
+
|
|
15955
16128
|
// Functions for dividing polygons and polygons at points where arc-segments intersect
|
|
15956
16129
|
|
|
15957
16130
|
// TODO:
|
|
@@ -16041,68 +16214,6 @@
|
|
|
16041
16214
|
}
|
|
16042
16215
|
|
|
16043
16216
|
|
|
16044
|
-
// Remap any references to duplicate arcs in paths to use the same arcs
|
|
16045
|
-
// Remove any unused arcs from the dataset's ArcCollection.
|
|
16046
|
-
// Return a NodeCollection
|
|
16047
|
-
function cleanArcReferences(dataset) {
|
|
16048
|
-
var nodes = new NodeCollection(dataset.arcs);
|
|
16049
|
-
var map = findDuplicateArcs(nodes);
|
|
16050
|
-
var dropCount;
|
|
16051
|
-
if (map) {
|
|
16052
|
-
replaceIndexedArcIds(dataset, map);
|
|
16053
|
-
}
|
|
16054
|
-
dropCount = deleteUnusedArcs(dataset);
|
|
16055
|
-
if (dropCount > 0) {
|
|
16056
|
-
// rebuild nodes if arcs have changed
|
|
16057
|
-
nodes = new NodeCollection(dataset.arcs);
|
|
16058
|
-
}
|
|
16059
|
-
return nodes;
|
|
16060
|
-
}
|
|
16061
|
-
|
|
16062
|
-
|
|
16063
|
-
// @map an Object mapping old to new ids
|
|
16064
|
-
function replaceIndexedArcIds(dataset, map) {
|
|
16065
|
-
var remapPath = function(ids) {
|
|
16066
|
-
var arcId, absId, id2;
|
|
16067
|
-
for (var i=0; i<ids.length; i++) {
|
|
16068
|
-
arcId = ids[i];
|
|
16069
|
-
absId = absArcId(arcId);
|
|
16070
|
-
id2 = map[absId];
|
|
16071
|
-
ids[i] = arcId == absId ? id2 : ~id2;
|
|
16072
|
-
}
|
|
16073
|
-
return ids;
|
|
16074
|
-
};
|
|
16075
|
-
dataset.layers.forEach(function(lyr) {
|
|
16076
|
-
if (layerHasPaths(lyr)) {
|
|
16077
|
-
editShapes(lyr.shapes, remapPath);
|
|
16078
|
-
}
|
|
16079
|
-
});
|
|
16080
|
-
}
|
|
16081
|
-
|
|
16082
|
-
function findDuplicateArcs(nodes) {
|
|
16083
|
-
var map = new Int32Array(nodes.arcs.size()),
|
|
16084
|
-
count = 0,
|
|
16085
|
-
i2;
|
|
16086
|
-
for (var i=0, n=nodes.arcs.size(); i<n; i++) {
|
|
16087
|
-
i2 = nodes.findDuplicateArc(i);
|
|
16088
|
-
map[i] = i2;
|
|
16089
|
-
if (i != i2) count++;
|
|
16090
|
-
}
|
|
16091
|
-
return count > 0 ? map : null;
|
|
16092
|
-
}
|
|
16093
|
-
|
|
16094
|
-
function deleteUnusedArcs(dataset) {
|
|
16095
|
-
var test = getArcPresenceTest2(dataset.layers, dataset.arcs);
|
|
16096
|
-
var count1 = dataset.arcs.size();
|
|
16097
|
-
var map = dataset.arcs.deleteArcs(test); // condenses arcs
|
|
16098
|
-
var count2 = dataset.arcs.size();
|
|
16099
|
-
var deleteCount = count1 - count2;
|
|
16100
|
-
if (deleteCount > 0) {
|
|
16101
|
-
replaceIndexedArcIds(dataset, map);
|
|
16102
|
-
}
|
|
16103
|
-
return deleteCount;
|
|
16104
|
-
}
|
|
16105
|
-
|
|
16106
16217
|
// Return a function for updating a path (array of arc ids)
|
|
16107
16218
|
// @map array generated by insertCutPoints()
|
|
16108
16219
|
// @arcCount number of arcs in divided collection (kludge)
|
|
@@ -17458,8 +17569,9 @@
|
|
|
17458
17569
|
exporter = GeoJSON.exporters[lyr.geometry_type],
|
|
17459
17570
|
geom = shape ? exporter(shape, dataset.arcs, opts) : null,
|
|
17460
17571
|
obj = null;
|
|
17572
|
+
|
|
17461
17573
|
if (asFeatures) {
|
|
17462
|
-
obj =
|
|
17574
|
+
obj = composeFeature(geom, properties ? properties[i] : null, opts);
|
|
17463
17575
|
if (ids) {
|
|
17464
17576
|
obj.id = ids[i];
|
|
17465
17577
|
}
|
|
@@ -17483,6 +17595,20 @@
|
|
|
17483
17595
|
}, []);
|
|
17484
17596
|
}
|
|
17485
17597
|
|
|
17598
|
+
function composeFeature(geom, properties, opts) {
|
|
17599
|
+
var feat = GeoJSON.toFeature(geom, properties);
|
|
17600
|
+
if (Array.isArray(opts.hoist) && properties) {
|
|
17601
|
+
// don't modify properties of source feature
|
|
17602
|
+
feat.properties = Object.assign({}, properties);
|
|
17603
|
+
opts.hoist.forEach(field => {
|
|
17604
|
+
if (properties.hasOwnProperty(field)) {
|
|
17605
|
+
feat[field] = properties[field];
|
|
17606
|
+
delete feat.properties[field];
|
|
17607
|
+
}
|
|
17608
|
+
});
|
|
17609
|
+
}
|
|
17610
|
+
return feat;
|
|
17611
|
+
}
|
|
17486
17612
|
|
|
17487
17613
|
function getRFC7946Warnings(dataset) {
|
|
17488
17614
|
var P = getDatasetCRS(dataset);
|
|
@@ -21576,6 +21702,14 @@ ${svg}
|
|
|
21576
21702
|
}
|
|
21577
21703
|
return memo.concat(exportFileContent(dataset, opts));
|
|
21578
21704
|
}, []);
|
|
21705
|
+
|
|
21706
|
+
if (opts.bbox_index) {
|
|
21707
|
+
// If rounding or quantization are applied during export, bounds may
|
|
21708
|
+
// change somewhat... consider adding a bounds property to each layer during
|
|
21709
|
+
// export when appropriate.
|
|
21710
|
+
files.push(createIndexFile(datasets));
|
|
21711
|
+
}
|
|
21712
|
+
|
|
21579
21713
|
// need unique names for multiple output files
|
|
21580
21714
|
assignUniqueFileNames(files);
|
|
21581
21715
|
|
|
@@ -21633,15 +21767,7 @@ ${svg}
|
|
|
21633
21767
|
}
|
|
21634
21768
|
|
|
21635
21769
|
validateLayerData(dataset.layers);
|
|
21636
|
-
|
|
21637
21770
|
files = exporter(dataset, opts).concat(files);
|
|
21638
|
-
// If rounding or quantization are applied during export, bounds may
|
|
21639
|
-
// change somewhat... consider adding a bounds property to each layer during
|
|
21640
|
-
// export when appropriate.
|
|
21641
|
-
if (opts.bbox_index) {
|
|
21642
|
-
files.push(createIndexFile(dataset));
|
|
21643
|
-
}
|
|
21644
|
-
|
|
21645
21771
|
validateFileNames(files);
|
|
21646
21772
|
return files;
|
|
21647
21773
|
}
|
|
@@ -21662,13 +21788,16 @@ ${svg}
|
|
|
21662
21788
|
// Generate json file with bounding boxes and names of each export layer
|
|
21663
21789
|
// TODO: consider making this a command, or at least make format settable
|
|
21664
21790
|
//
|
|
21665
|
-
function createIndexFile(
|
|
21666
|
-
var index =
|
|
21667
|
-
|
|
21668
|
-
|
|
21669
|
-
|
|
21670
|
-
|
|
21671
|
-
|
|
21791
|
+
function createIndexFile(datasets) {
|
|
21792
|
+
var index = [];
|
|
21793
|
+
datasets.forEach(function(dataset) {
|
|
21794
|
+
dataset.layers.forEach(function(lyr) {
|
|
21795
|
+
var bounds = getLayerBounds(lyr, dataset.arcs);
|
|
21796
|
+
index.push({
|
|
21797
|
+
bbox: bounds.toArray(),
|
|
21798
|
+
name: lyr.name
|
|
21799
|
+
});
|
|
21800
|
+
});
|
|
21672
21801
|
});
|
|
21673
21802
|
|
|
21674
21803
|
return {
|
|
@@ -23391,7 +23520,7 @@ ${svg}
|
|
|
23391
23520
|
.option('string-fields', stringFieldsOpt)
|
|
23392
23521
|
.option('field-types', fieldTypesOpt)
|
|
23393
23522
|
.option('name', {
|
|
23394
|
-
describe: '
|
|
23523
|
+
describe: 'rename the imported layer(s)'
|
|
23395
23524
|
})
|
|
23396
23525
|
.option('geometry-type', {
|
|
23397
23526
|
// undocumented; GeoJSON import rejects all but one kind of geometry
|
|
@@ -23560,6 +23689,10 @@ ${svg}
|
|
|
23560
23689
|
describe: '[GeoJSON/JSON] output newline-delimited features or records',
|
|
23561
23690
|
type: 'flag'
|
|
23562
23691
|
})
|
|
23692
|
+
.option('hoist', {
|
|
23693
|
+
describe: '[GeoJSON] move properties to the root level of each Feature',
|
|
23694
|
+
type: 'strings'
|
|
23695
|
+
})
|
|
23563
23696
|
.option('width', {
|
|
23564
23697
|
describe: '[SVG/TopoJSON] pixel width of output (SVG default is 800)',
|
|
23565
23698
|
type: 'number'
|
|
@@ -33318,7 +33451,7 @@ ${svg}
|
|
|
33318
33451
|
if (n != values.length) {
|
|
33319
33452
|
stop('Mismatch in number of categories and number of values');
|
|
33320
33453
|
}
|
|
33321
|
-
return values;
|
|
33454
|
+
return parseValues(values); // convert numerical strings to numbers
|
|
33322
33455
|
}
|
|
33323
33456
|
|
|
33324
33457
|
function getIndexes(n) {
|
|
@@ -33486,7 +33619,7 @@ ${svg}
|
|
|
33486
33619
|
if (opts.index_field) {
|
|
33487
33620
|
dataField = opts.index_field;
|
|
33488
33621
|
fieldType = getColumnType(opts.field, records);
|
|
33489
|
-
|
|
33622
|
+
} else if (opts.field) {
|
|
33490
33623
|
dataField = opts.field;
|
|
33491
33624
|
fieldType = getColumnType(opts.field, records);
|
|
33492
33625
|
}
|
|
@@ -33510,7 +33643,6 @@ ${svg}
|
|
|
33510
33643
|
stop('Missing a data field to classify');
|
|
33511
33644
|
}
|
|
33512
33645
|
|
|
33513
|
-
|
|
33514
33646
|
// get the number of classes and the number of values
|
|
33515
33647
|
//
|
|
33516
33648
|
// expand categories if value is '*'
|
|
@@ -33519,6 +33651,9 @@ ${svg}
|
|
|
33519
33651
|
if ((!opts.categories || opts.categories.includes('*')) && dataField) {
|
|
33520
33652
|
opts.categories = getUniqFieldValues(records, dataField);
|
|
33521
33653
|
}
|
|
33654
|
+
if (opts.categories && fieldType == 'number') {
|
|
33655
|
+
opts.categories = opts.categories.map(str => +str);
|
|
33656
|
+
}
|
|
33522
33657
|
}
|
|
33523
33658
|
|
|
33524
33659
|
if (opts.classes) {
|
|
@@ -34663,34 +34798,48 @@ ${svg}
|
|
|
34663
34798
|
}
|
|
34664
34799
|
|
|
34665
34800
|
function getFeatureEditor(lyr, dataset) {
|
|
34666
|
-
var changed = false;
|
|
34667
34801
|
var api = {};
|
|
34668
34802
|
// need to copy attribute to avoid circular references if geojson is assigned
|
|
34669
34803
|
// to a data property.
|
|
34670
34804
|
var copy = copyLayer(lyr);
|
|
34671
34805
|
var features = exportLayerAsGeoJSON(copy, dataset, {}, true);
|
|
34806
|
+
var features2 = [];
|
|
34672
34807
|
|
|
34673
34808
|
api.get = function(i) {
|
|
34809
|
+
if (i > 0) features[i-1] = null; // garbage-collect old features
|
|
34674
34810
|
return features[i];
|
|
34675
34811
|
};
|
|
34676
34812
|
|
|
34677
34813
|
api.set = function(feat, i) {
|
|
34678
|
-
|
|
34814
|
+
var arr;
|
|
34815
|
+
|
|
34679
34816
|
if (utils.isString(feat)) {
|
|
34680
34817
|
feat = JSON.parse(feat);
|
|
34681
34818
|
}
|
|
34682
|
-
|
|
34819
|
+
|
|
34820
|
+
if (!feat) return;
|
|
34821
|
+
|
|
34822
|
+
if (feat.type == 'GeometryCollection') {
|
|
34823
|
+
arr = feat.geometries.map(geom => GeoJSON.toFeature(geom));
|
|
34824
|
+
} else if (feat.type == 'FeatureCollection') {
|
|
34825
|
+
arr = feat.features;
|
|
34826
|
+
} else {
|
|
34827
|
+
feat = GeoJSON.toFeature(feat);
|
|
34828
|
+
}
|
|
34829
|
+
|
|
34830
|
+
if (arr) {
|
|
34831
|
+
features2 = features2.concat(arr);
|
|
34832
|
+
} else {
|
|
34833
|
+
features2.push(feat);
|
|
34834
|
+
}
|
|
34683
34835
|
};
|
|
34684
34836
|
|
|
34685
34837
|
api.done = function() {
|
|
34686
|
-
if (
|
|
34687
|
-
// TODO: validate number of features, etc.
|
|
34838
|
+
if (features2.length === 0) return; // read-only expression
|
|
34688
34839
|
var geojson = {
|
|
34689
34840
|
type: 'FeatureCollection',
|
|
34690
|
-
features:
|
|
34841
|
+
features: features2
|
|
34691
34842
|
};
|
|
34692
|
-
|
|
34693
|
-
// console.log(JSON.stringify(geojson, null, 2))
|
|
34694
34843
|
return importGeoJSON(geojson);
|
|
34695
34844
|
};
|
|
34696
34845
|
return api;
|
|
@@ -40453,9 +40602,8 @@ ${svg}
|
|
|
40453
40602
|
cmd.polygonGrid = function(targetLayers, targetDataset, opts) {
|
|
40454
40603
|
requireProjectedDataset(targetDataset);
|
|
40455
40604
|
var params = getGridParams(targetLayers, targetDataset, opts);
|
|
40456
|
-
var gridDataset = makeGridDataset(params);
|
|
40457
|
-
|
|
40458
|
-
gridDataset.info = targetDataset.info; // copy CRS to grid dataset // TODO: improve
|
|
40605
|
+
var gridDataset = makeGridDataset(params); // grid is a new dataset
|
|
40606
|
+
gridDataset.info = copyDatasetInfo(targetDataset.info);
|
|
40459
40607
|
setOutputLayerName(gridDataset.layers[0], null, 'grid', opts);
|
|
40460
40608
|
if (opts.debug) gridDataset.layers.push(cmd.pointGrid2(targetLayers, targetDataset, opts));
|
|
40461
40609
|
return gridDataset;
|