mapshaper 0.7.5 → 0.7.6
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 +134 -36
- package/package.json +1 -1
- package/www/mapshaper.js +134 -36
package/mapshaper.js
CHANGED
|
@@ -4629,6 +4629,32 @@
|
|
|
4629
4629
|
return inputs && inputs[0] || '';
|
|
4630
4630
|
}
|
|
4631
4631
|
|
|
4632
|
+
// Return layers in @dataset that were *not* selected by the current target
|
|
4633
|
+
// set but still match a command-specific geometry predicate.
|
|
4634
|
+
//
|
|
4635
|
+
// Used for command side-effect messaging, e.g.:
|
|
4636
|
+
// - -proj (shared dataset reprojection)
|
|
4637
|
+
// - -simplify (shared arc simplification)
|
|
4638
|
+
//
|
|
4639
|
+
// @targetLayers should be the layer selection that triggered the command.
|
|
4640
|
+
// If all layers are targeted (or target selection is missing), returns [].
|
|
4641
|
+
// @filterFn optional predicate (lyr -> bool) for command-specific relevance.
|
|
4642
|
+
function getImplicitlyTargetedLayers(dataset, targetLayers, filterFn) {
|
|
4643
|
+
if (!targetLayers || targetLayers.length === 0 || targetLayers.length >= dataset.layers.length) {
|
|
4644
|
+
return [];
|
|
4645
|
+
}
|
|
4646
|
+
var targeted = new Set(targetLayers);
|
|
4647
|
+
return dataset.layers.filter(function(lyr) {
|
|
4648
|
+
return !targeted.has(lyr) && (!filterFn || filterFn(lyr));
|
|
4649
|
+
});
|
|
4650
|
+
}
|
|
4651
|
+
|
|
4652
|
+
function getImplicitlyTargetedLayerNames(dataset, targetLayers, filterFn) {
|
|
4653
|
+
return getImplicitlyTargetedLayers(dataset, targetLayers, filterFn).map(function(lyr) {
|
|
4654
|
+
return lyr.name || '[unnamed]';
|
|
4655
|
+
});
|
|
4656
|
+
}
|
|
4657
|
+
|
|
4632
4658
|
// Divide a collection of features with mixed types into layers of a single type
|
|
4633
4659
|
// (Used for importing TopoJSON and GeoJSON features)
|
|
4634
4660
|
function divideFeaturesByType(shapes, properties, types) {
|
|
@@ -4769,6 +4795,8 @@
|
|
|
4769
4795
|
filterPathLayerByArcIds: filterPathLayerByArcIds,
|
|
4770
4796
|
getArcPresenceTest2: getArcPresenceTest2,
|
|
4771
4797
|
getFeatureCount: getFeatureCount,
|
|
4798
|
+
getImplicitlyTargetedLayerNames: getImplicitlyTargetedLayerNames,
|
|
4799
|
+
getImplicitlyTargetedLayers: getImplicitlyTargetedLayers,
|
|
4772
4800
|
getLayerBounds: getLayerBounds,
|
|
4773
4801
|
getLayerDataTable: getLayerDataTable,
|
|
4774
4802
|
getLayerSourceFile: getLayerSourceFile,
|
|
@@ -19446,7 +19474,9 @@ ${svg}
|
|
|
19446
19474
|
|
|
19447
19475
|
function exportDbfFile(lyr, dataset, opts) {
|
|
19448
19476
|
var data = lyr.data,
|
|
19449
|
-
buf
|
|
19477
|
+
buf,
|
|
19478
|
+
files,
|
|
19479
|
+
encoding;
|
|
19450
19480
|
// create empty data table if missing a table or table is being cut out
|
|
19451
19481
|
if (!data || opts.cut_table || opts.drop_table) {
|
|
19452
19482
|
data = new DataTable(lyr.shapes ? lyr.shapes.length : 0);
|
|
@@ -19460,14 +19490,34 @@ ${svg}
|
|
|
19460
19490
|
} else {
|
|
19461
19491
|
buf = Dbf.exportRecords(data.getRecords(), opts.encoding, opts.field_order);
|
|
19462
19492
|
}
|
|
19493
|
+
encoding = getDbfExportEncoding(data, opts);
|
|
19463
19494
|
if (utils.isInteger(opts.ldid)) {
|
|
19464
19495
|
new Uint8Array(buf)[29] = opts.ldid; // set language driver id
|
|
19465
19496
|
}
|
|
19466
|
-
|
|
19467
|
-
return [{
|
|
19497
|
+
files = [{
|
|
19468
19498
|
content: buf,
|
|
19469
19499
|
filename: lyr.name + '.dbf'
|
|
19470
19500
|
}];
|
|
19501
|
+
if (opts.export_cpg && encoding) {
|
|
19502
|
+
files.push({
|
|
19503
|
+
content: formatCpgEncoding(encoding),
|
|
19504
|
+
filename: lyr.name + '.cpg'
|
|
19505
|
+
});
|
|
19506
|
+
}
|
|
19507
|
+
return files;
|
|
19508
|
+
}
|
|
19509
|
+
|
|
19510
|
+
function getDbfExportEncoding(data, opts) {
|
|
19511
|
+
if (data && data.getDbfEncoding) {
|
|
19512
|
+
return data.getDbfEncoding(opts);
|
|
19513
|
+
}
|
|
19514
|
+
return opts.encoding || 'utf8';
|
|
19515
|
+
}
|
|
19516
|
+
|
|
19517
|
+
function formatCpgEncoding(encoding) {
|
|
19518
|
+
// Canonical spelling for the default.
|
|
19519
|
+
if (/^utf-?8$/i.test(String(encoding))) return 'UTF-8';
|
|
19520
|
+
return String(encoding);
|
|
19471
19521
|
}
|
|
19472
19522
|
|
|
19473
19523
|
var decoder;
|
|
@@ -22232,8 +22282,9 @@ ${svg}
|
|
|
22232
22282
|
function exportShapefile(dataset, opts) {
|
|
22233
22283
|
return dataset.layers.reduce(function(files, lyr) {
|
|
22234
22284
|
var prj = exportPrjFile(lyr, dataset);
|
|
22285
|
+
var dbfOpts = utils.defaults({export_cpg: true}, opts);
|
|
22235
22286
|
files = files.concat(exportShpAndShxFiles(lyr, dataset));
|
|
22236
|
-
files = files.concat(exportDbfFile(lyr, dataset,
|
|
22287
|
+
files = files.concat(exportDbfFile(lyr, dataset, dbfOpts));
|
|
22237
22288
|
if (prj) files.push(prj);
|
|
22238
22289
|
return files;
|
|
22239
22290
|
}, []);
|
|
@@ -30251,6 +30302,7 @@ ${svg}
|
|
|
30251
30302
|
};
|
|
30252
30303
|
|
|
30253
30304
|
this.getFields = getFieldNames;
|
|
30305
|
+
this.getEncoding = getEncoding;
|
|
30254
30306
|
|
|
30255
30307
|
// TODO: switch to streaming output under Node.js
|
|
30256
30308
|
this.getBuffer = function() {
|
|
@@ -30570,6 +30622,19 @@ ${svg}
|
|
|
30570
30622
|
return Dbf.exportRecords(getTable().getRecords(), opts.encoding, opts.field_order);
|
|
30571
30623
|
};
|
|
30572
30624
|
|
|
30625
|
+
// Return the text encoding that exportAsDbf() will use for the current
|
|
30626
|
+
// options. If we're exporting the untouched original DBF bytes, use the
|
|
30627
|
+
// reader's detected/declared encoding; otherwise we regenerate with either
|
|
30628
|
+
// opts.encoding or the writer default (utf8).
|
|
30629
|
+
this.getDbfEncoding = function(optsArg) {
|
|
30630
|
+
var opts = optsArg || {};
|
|
30631
|
+
var useOriginal = !!reader && !altered && !opts.field_order && !opts.encoding;
|
|
30632
|
+
if (useOriginal) {
|
|
30633
|
+
return reader.getEncoding();
|
|
30634
|
+
}
|
|
30635
|
+
return opts.encoding || 'utf8';
|
|
30636
|
+
};
|
|
30637
|
+
|
|
30573
30638
|
this.getReadOnlyRecordAt = function(i) {
|
|
30574
30639
|
return reader ? reader.readRow(i) : table.getReadOnlyRecordAt(i);
|
|
30575
30640
|
};
|
|
@@ -31409,7 +31474,7 @@ ${svg}
|
|
|
31409
31474
|
(srcCollection.features || srcCollection.geometries || []).forEach(importer.parseObject);
|
|
31410
31475
|
dataset = importer.done();
|
|
31411
31476
|
importCRS(dataset, srcObj); // TODO: remove this
|
|
31412
|
-
warnIfProjectedCoords(dataset, srcObj);
|
|
31477
|
+
warnIfProjectedCoords(dataset, srcObj, opts);
|
|
31413
31478
|
return dataset;
|
|
31414
31479
|
}
|
|
31415
31480
|
|
|
@@ -31417,12 +31482,13 @@ ${svg}
|
|
|
31417
31482
|
// `crs` member). If the imported file makes no CRS claim but its coordinates
|
|
31418
31483
|
// are clearly outside lat-long range, warn the user: silent fallthrough here
|
|
31419
31484
|
// usually surfaces later as cryptic -proj errors or grossly wrong output.
|
|
31420
|
-
function warnIfProjectedCoords(dataset, jsonObj) {
|
|
31485
|
+
function warnIfProjectedCoords(dataset, jsonObj, opts) {
|
|
31486
|
+
if (!opts.warn_projected_coords) return;
|
|
31421
31487
|
if (jsonObj && jsonObj.crs) return; // user has explicitly declared a CRS
|
|
31422
31488
|
var bounds = getRoughDatasetBounds(dataset);
|
|
31423
31489
|
if (!bounds || !bounds.hasBounds()) return;
|
|
31424
31490
|
if (probablyDecimalDegreeBounds(bounds)) return;
|
|
31425
|
-
warn('Imported GeoJSON has coordinates outside the lat-long range
|
|
31491
|
+
warn('Imported GeoJSON has coordinates outside the lat-long range -- ' +
|
|
31426
31492
|
' importing as projected geometry with unknown CRS. Commands ' +
|
|
31427
31493
|
'like -proj that require a CRS will not work until you set a source ' +
|
|
31428
31494
|
'CRS, e.g. -proj init=EPSG:3857.');
|
|
@@ -32485,7 +32551,7 @@ ${svg}
|
|
|
32485
32551
|
if (fmt == 'topojson') {
|
|
32486
32552
|
retn.dataset = importTopoJSON(content, opts);
|
|
32487
32553
|
} else if (fmt == 'geojson') {
|
|
32488
|
-
retn.dataset = importGeoJSON(content, opts);
|
|
32554
|
+
retn.dataset = importGeoJSON(content, getGeoJSONImportOpts(opts));
|
|
32489
32555
|
} else if (fmt == 'json') {
|
|
32490
32556
|
retn.dataset = importJSONTable(content);
|
|
32491
32557
|
} else {
|
|
@@ -32497,6 +32563,12 @@ ${svg}
|
|
|
32497
32563
|
return retn;
|
|
32498
32564
|
}
|
|
32499
32565
|
|
|
32566
|
+
function getGeoJSONImportOpts(opts) {
|
|
32567
|
+
return Object.assign({}, opts, {
|
|
32568
|
+
warn_projected_coords: true
|
|
32569
|
+
});
|
|
32570
|
+
}
|
|
32571
|
+
|
|
32500
32572
|
// path: path from top-level to the target object
|
|
32501
32573
|
function selectFromObject(o, path) {
|
|
32502
32574
|
var arrayRxp = /(.*)\[([0-9]+)\]$/; // array bracket notation w/ index
|
|
@@ -43429,20 +43501,24 @@ ${svg}
|
|
|
43429
43501
|
}
|
|
43430
43502
|
}
|
|
43431
43503
|
|
|
43432
|
-
|
|
43433
|
-
|
|
43434
|
-
|
|
43435
|
-
|
|
43436
|
-
|
|
43437
|
-
|
|
43438
|
-
|
|
43439
|
-
|
|
43440
|
-
|
|
43441
|
-
|
|
43442
|
-
|
|
43443
|
-
|
|
43444
|
-
|
|
43445
|
-
|
|
43504
|
+
// Opt-in summary logging. Some commands (e.g. -divide) reuse this join
|
|
43505
|
+
// helper internally and don't want user-facing join diagnostics.
|
|
43506
|
+
if (opts.show_join_message) {
|
|
43507
|
+
printJoinMessage({
|
|
43508
|
+
matches: matchCount,
|
|
43509
|
+
n: n,
|
|
43510
|
+
joins: countJoins(joinCounts),
|
|
43511
|
+
m: srcRecords.length,
|
|
43512
|
+
skipped: skipCount,
|
|
43513
|
+
collisions: collisionCount,
|
|
43514
|
+
collisionFields: collisionFields,
|
|
43515
|
+
destKey: destKey,
|
|
43516
|
+
srcKey: srcKey,
|
|
43517
|
+
unmatchedTargetKeys: takeSampleKeys(unmatchedTargetKeys),
|
|
43518
|
+
unusedSourceKeys: takeSampleKeys(unusedSourceKeys),
|
|
43519
|
+
opts: opts
|
|
43520
|
+
});
|
|
43521
|
+
}
|
|
43446
43522
|
|
|
43447
43523
|
if (opts.unjoined) {
|
|
43448
43524
|
retn.unjoined = {
|
|
@@ -46804,7 +46880,7 @@ ${svg}
|
|
|
46804
46880
|
// Works for lcc, aea, tmerc, etc.
|
|
46805
46881
|
// TODO: add more projections
|
|
46806
46882
|
//
|
|
46807
|
-
function expandProjDefn(str, dataset) {
|
|
46883
|
+
function expandProjDefn(str, dataset, targetLayers) {
|
|
46808
46884
|
var mproj = require$1('mproj');
|
|
46809
46885
|
var proj4, params, bbox, isConic2SP, isCentered, decimals;
|
|
46810
46886
|
if (str in mproj.internal.pj_list === false) {
|
|
@@ -46815,7 +46891,7 @@ ${svg}
|
|
|
46815
46891
|
isCentered = ['tmerc', 'etmerc'].includes(str);
|
|
46816
46892
|
proj4 = '+proj=' + str;
|
|
46817
46893
|
if (isConic2SP || isCentered) {
|
|
46818
|
-
bbox = getBBox(dataset); // TODO: support projected datasets
|
|
46894
|
+
bbox = getBBox(dataset, targetLayers); // TODO: support projected datasets
|
|
46819
46895
|
decimals = getBoundsPrecisionForDisplay(bbox);
|
|
46820
46896
|
params = isCentered ? getCenterParams(bbox, decimals) : getConicParams(bbox, decimals);
|
|
46821
46897
|
proj4 += ' ' + params;
|
|
@@ -46824,11 +46900,16 @@ ${svg}
|
|
|
46824
46900
|
return proj4;
|
|
46825
46901
|
}
|
|
46826
46902
|
|
|
46827
|
-
function getBBox(dataset) {
|
|
46903
|
+
function getBBox(dataset, targetLayers) {
|
|
46904
|
+
var source = targetLayers && targetLayers.length > 0 ? {
|
|
46905
|
+
arcs: dataset.arcs,
|
|
46906
|
+
layers: targetLayers,
|
|
46907
|
+
info: dataset.info
|
|
46908
|
+
} : dataset;
|
|
46828
46909
|
if (!isLatLngCRS(getDatasetCRS(dataset))) {
|
|
46829
46910
|
stop$1('Expected unprojected data');
|
|
46830
46911
|
}
|
|
46831
|
-
return getDatasetBounds(
|
|
46912
|
+
return getDatasetBounds(source).toArray();
|
|
46832
46913
|
}
|
|
46833
46914
|
|
|
46834
46915
|
// See: Savric & Jenny, "Automating the selection of standard parallels for conic map projections"
|
|
@@ -46854,8 +46935,9 @@ ${svg}
|
|
|
46854
46935
|
getConicParams: getConicParams
|
|
46855
46936
|
});
|
|
46856
46937
|
|
|
46857
|
-
cmd.proj = function(dataset, catalog, opts) {
|
|
46938
|
+
cmd.proj = function(dataset, catalog, opts, targetLayers) {
|
|
46858
46939
|
var srcInfo, destInfo, destStr;
|
|
46940
|
+
var implicitlyProjectedNames = getImplicitlyTargetedLayerNames(dataset, targetLayers, layerHasGeometry);
|
|
46859
46941
|
if (opts.init) {
|
|
46860
46942
|
srcInfo = fetchCrsInfo(opts.init, catalog);
|
|
46861
46943
|
if (!srcInfo.crs) stop$1("Unknown projection source:", opts.init);
|
|
@@ -46864,11 +46946,17 @@ ${svg}
|
|
|
46864
46946
|
if (opts.match) {
|
|
46865
46947
|
destInfo = fetchCrsInfo(opts.match, catalog);
|
|
46866
46948
|
} else if (opts.crs) {
|
|
46867
|
-
destStr = expandProjDefn(opts.crs, dataset);
|
|
46949
|
+
destStr = expandProjDefn(opts.crs, dataset, targetLayers);
|
|
46868
46950
|
destInfo = getCrsInfo(destStr);
|
|
46869
46951
|
}
|
|
46870
46952
|
if (destInfo) {
|
|
46871
|
-
projCmd(dataset, destInfo, opts);
|
|
46953
|
+
var didProject = projCmd(dataset, destInfo, opts);
|
|
46954
|
+
if (didProject && implicitlyProjectedNames.length > 0) {
|
|
46955
|
+
message(
|
|
46956
|
+
'Also projected non-target layer' + utils.pluralSuffix(implicitlyProjectedNames.length) +
|
|
46957
|
+
' from the same dataset: ' + implicitlyProjectedNames.join(', ')
|
|
46958
|
+
);
|
|
46959
|
+
}
|
|
46872
46960
|
}
|
|
46873
46961
|
};
|
|
46874
46962
|
|
|
@@ -46886,7 +46974,7 @@ ${svg}
|
|
|
46886
46974
|
if (!datasetHasGeometry(dataset)) {
|
|
46887
46975
|
// still set the crs of datasets that are missing geometry
|
|
46888
46976
|
setDatasetCrsInfo(dataset, destInfo);
|
|
46889
|
-
return;
|
|
46977
|
+
return false;
|
|
46890
46978
|
}
|
|
46891
46979
|
|
|
46892
46980
|
var srcInfo = getDatasetCrsInfo(dataset);
|
|
@@ -46896,7 +46984,7 @@ ${svg}
|
|
|
46896
46984
|
|
|
46897
46985
|
if (crsAreEqual(srcInfo.crs, destInfo.crs)) {
|
|
46898
46986
|
message("Source and destination CRS are the same");
|
|
46899
|
-
return;
|
|
46987
|
+
return false;
|
|
46900
46988
|
}
|
|
46901
46989
|
|
|
46902
46990
|
if (dataset.arcs) {
|
|
@@ -46922,9 +47010,9 @@ ${svg}
|
|
|
46922
47010
|
// replace original layers with modified layers
|
|
46923
47011
|
utils.extend(lyr, target.layers[i]);
|
|
46924
47012
|
});
|
|
47013
|
+
return true;
|
|
46925
47014
|
}
|
|
46926
47015
|
|
|
46927
|
-
|
|
46928
47016
|
// name: a layer identifier, .prj file or projection defn
|
|
46929
47017
|
// Converts layer ids and .prj files to CRS defn
|
|
46930
47018
|
// Returns projection defn
|
|
@@ -48477,6 +48565,9 @@ ${svg}
|
|
|
48477
48565
|
}
|
|
48478
48566
|
|
|
48479
48567
|
cmd.join = function(targetLyr, targetDataset, src, opts) {
|
|
48568
|
+
// Opt in to the post-join summary emitted by joinTableToLayer().
|
|
48569
|
+
// Other commands can reuse the helper without showing this message.
|
|
48570
|
+
opts = Object.assign({}, opts, {show_join_message: true});
|
|
48480
48571
|
var srcType, targetType, retn;
|
|
48481
48572
|
if (!src || !src.dataset) {
|
|
48482
48573
|
stop$1("Missing a joinable data source");
|
|
@@ -51094,8 +51185,9 @@ ${svg}
|
|
|
51094
51185
|
replaceInArray: replaceInArray
|
|
51095
51186
|
});
|
|
51096
51187
|
|
|
51097
|
-
cmd.simplify = function(dataset, opts) {
|
|
51188
|
+
cmd.simplify = function(dataset, opts, targetLayers) {
|
|
51098
51189
|
var arcs = dataset.arcs;
|
|
51190
|
+
var implicitlySimplifiedNames = getImplicitlyTargetedLayerNames(dataset, targetLayers, layerHasPaths);
|
|
51099
51191
|
if (!arcs || arcs.size() === 0) return; // removed in v0.4.125: stop("Missing path data");
|
|
51100
51192
|
opts = getStandardSimplifyOpts(dataset, opts); // standardize options
|
|
51101
51193
|
simplifyPaths(arcs, opts);
|
|
@@ -51114,6 +51206,12 @@ ${svg}
|
|
|
51114
51206
|
}
|
|
51115
51207
|
|
|
51116
51208
|
finalizeSimplification(dataset, opts);
|
|
51209
|
+
if (implicitlySimplifiedNames.length > 0) {
|
|
51210
|
+
message(
|
|
51211
|
+
'Also simplified non-target layer' + utils.pluralSuffix(implicitlySimplifiedNames.length) +
|
|
51212
|
+
' from the same dataset: ' + implicitlySimplifiedNames.join(', ')
|
|
51213
|
+
);
|
|
51214
|
+
}
|
|
51117
51215
|
};
|
|
51118
51216
|
|
|
51119
51217
|
function finalizeSimplification(dataset, opts) {
|
|
@@ -52807,7 +52905,7 @@ ${svg}
|
|
|
52807
52905
|
await initProjLibrary(opts);
|
|
52808
52906
|
job.resumeCommand();
|
|
52809
52907
|
targets.forEach(function(targ) {
|
|
52810
|
-
cmd.proj(targ.dataset, job.catalog, opts);
|
|
52908
|
+
cmd.proj(targ.dataset, job.catalog, opts, targ.layers);
|
|
52811
52909
|
});
|
|
52812
52910
|
|
|
52813
52911
|
} else if (name == 'rectangle') {
|
|
@@ -52850,7 +52948,7 @@ ${svg}
|
|
|
52850
52948
|
if (opts.variable) {
|
|
52851
52949
|
cmd.variableSimplify(targetLayers, targetDataset, opts);
|
|
52852
52950
|
} else {
|
|
52853
|
-
cmd.simplify(targetDataset, opts);
|
|
52951
|
+
cmd.simplify(targetDataset, opts, targetLayers);
|
|
52854
52952
|
}
|
|
52855
52953
|
|
|
52856
52954
|
} else if (name == 'slice') {
|
|
@@ -52976,7 +53074,7 @@ ${svg}
|
|
|
52976
53074
|
});
|
|
52977
53075
|
}
|
|
52978
53076
|
|
|
52979
|
-
var version = "0.7.
|
|
53077
|
+
var version = "0.7.6";
|
|
52980
53078
|
|
|
52981
53079
|
// Parse command line args into commands and run them
|
|
52982
53080
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|
package/package.json
CHANGED
package/www/mapshaper.js
CHANGED
|
@@ -4629,6 +4629,32 @@
|
|
|
4629
4629
|
return inputs && inputs[0] || '';
|
|
4630
4630
|
}
|
|
4631
4631
|
|
|
4632
|
+
// Return layers in @dataset that were *not* selected by the current target
|
|
4633
|
+
// set but still match a command-specific geometry predicate.
|
|
4634
|
+
//
|
|
4635
|
+
// Used for command side-effect messaging, e.g.:
|
|
4636
|
+
// - -proj (shared dataset reprojection)
|
|
4637
|
+
// - -simplify (shared arc simplification)
|
|
4638
|
+
//
|
|
4639
|
+
// @targetLayers should be the layer selection that triggered the command.
|
|
4640
|
+
// If all layers are targeted (or target selection is missing), returns [].
|
|
4641
|
+
// @filterFn optional predicate (lyr -> bool) for command-specific relevance.
|
|
4642
|
+
function getImplicitlyTargetedLayers(dataset, targetLayers, filterFn) {
|
|
4643
|
+
if (!targetLayers || targetLayers.length === 0 || targetLayers.length >= dataset.layers.length) {
|
|
4644
|
+
return [];
|
|
4645
|
+
}
|
|
4646
|
+
var targeted = new Set(targetLayers);
|
|
4647
|
+
return dataset.layers.filter(function(lyr) {
|
|
4648
|
+
return !targeted.has(lyr) && (!filterFn || filterFn(lyr));
|
|
4649
|
+
});
|
|
4650
|
+
}
|
|
4651
|
+
|
|
4652
|
+
function getImplicitlyTargetedLayerNames(dataset, targetLayers, filterFn) {
|
|
4653
|
+
return getImplicitlyTargetedLayers(dataset, targetLayers, filterFn).map(function(lyr) {
|
|
4654
|
+
return lyr.name || '[unnamed]';
|
|
4655
|
+
});
|
|
4656
|
+
}
|
|
4657
|
+
|
|
4632
4658
|
// Divide a collection of features with mixed types into layers of a single type
|
|
4633
4659
|
// (Used for importing TopoJSON and GeoJSON features)
|
|
4634
4660
|
function divideFeaturesByType(shapes, properties, types) {
|
|
@@ -4769,6 +4795,8 @@
|
|
|
4769
4795
|
filterPathLayerByArcIds: filterPathLayerByArcIds,
|
|
4770
4796
|
getArcPresenceTest2: getArcPresenceTest2,
|
|
4771
4797
|
getFeatureCount: getFeatureCount,
|
|
4798
|
+
getImplicitlyTargetedLayerNames: getImplicitlyTargetedLayerNames,
|
|
4799
|
+
getImplicitlyTargetedLayers: getImplicitlyTargetedLayers,
|
|
4772
4800
|
getLayerBounds: getLayerBounds,
|
|
4773
4801
|
getLayerDataTable: getLayerDataTable,
|
|
4774
4802
|
getLayerSourceFile: getLayerSourceFile,
|
|
@@ -19446,7 +19474,9 @@ ${svg}
|
|
|
19446
19474
|
|
|
19447
19475
|
function exportDbfFile(lyr, dataset, opts) {
|
|
19448
19476
|
var data = lyr.data,
|
|
19449
|
-
buf
|
|
19477
|
+
buf,
|
|
19478
|
+
files,
|
|
19479
|
+
encoding;
|
|
19450
19480
|
// create empty data table if missing a table or table is being cut out
|
|
19451
19481
|
if (!data || opts.cut_table || opts.drop_table) {
|
|
19452
19482
|
data = new DataTable(lyr.shapes ? lyr.shapes.length : 0);
|
|
@@ -19460,14 +19490,34 @@ ${svg}
|
|
|
19460
19490
|
} else {
|
|
19461
19491
|
buf = Dbf.exportRecords(data.getRecords(), opts.encoding, opts.field_order);
|
|
19462
19492
|
}
|
|
19493
|
+
encoding = getDbfExportEncoding(data, opts);
|
|
19463
19494
|
if (utils.isInteger(opts.ldid)) {
|
|
19464
19495
|
new Uint8Array(buf)[29] = opts.ldid; // set language driver id
|
|
19465
19496
|
}
|
|
19466
|
-
|
|
19467
|
-
return [{
|
|
19497
|
+
files = [{
|
|
19468
19498
|
content: buf,
|
|
19469
19499
|
filename: lyr.name + '.dbf'
|
|
19470
19500
|
}];
|
|
19501
|
+
if (opts.export_cpg && encoding) {
|
|
19502
|
+
files.push({
|
|
19503
|
+
content: formatCpgEncoding(encoding),
|
|
19504
|
+
filename: lyr.name + '.cpg'
|
|
19505
|
+
});
|
|
19506
|
+
}
|
|
19507
|
+
return files;
|
|
19508
|
+
}
|
|
19509
|
+
|
|
19510
|
+
function getDbfExportEncoding(data, opts) {
|
|
19511
|
+
if (data && data.getDbfEncoding) {
|
|
19512
|
+
return data.getDbfEncoding(opts);
|
|
19513
|
+
}
|
|
19514
|
+
return opts.encoding || 'utf8';
|
|
19515
|
+
}
|
|
19516
|
+
|
|
19517
|
+
function formatCpgEncoding(encoding) {
|
|
19518
|
+
// Canonical spelling for the default.
|
|
19519
|
+
if (/^utf-?8$/i.test(String(encoding))) return 'UTF-8';
|
|
19520
|
+
return String(encoding);
|
|
19471
19521
|
}
|
|
19472
19522
|
|
|
19473
19523
|
var decoder;
|
|
@@ -22232,8 +22282,9 @@ ${svg}
|
|
|
22232
22282
|
function exportShapefile(dataset, opts) {
|
|
22233
22283
|
return dataset.layers.reduce(function(files, lyr) {
|
|
22234
22284
|
var prj = exportPrjFile(lyr, dataset);
|
|
22285
|
+
var dbfOpts = utils.defaults({export_cpg: true}, opts);
|
|
22235
22286
|
files = files.concat(exportShpAndShxFiles(lyr, dataset));
|
|
22236
|
-
files = files.concat(exportDbfFile(lyr, dataset,
|
|
22287
|
+
files = files.concat(exportDbfFile(lyr, dataset, dbfOpts));
|
|
22237
22288
|
if (prj) files.push(prj);
|
|
22238
22289
|
return files;
|
|
22239
22290
|
}, []);
|
|
@@ -30251,6 +30302,7 @@ ${svg}
|
|
|
30251
30302
|
};
|
|
30252
30303
|
|
|
30253
30304
|
this.getFields = getFieldNames;
|
|
30305
|
+
this.getEncoding = getEncoding;
|
|
30254
30306
|
|
|
30255
30307
|
// TODO: switch to streaming output under Node.js
|
|
30256
30308
|
this.getBuffer = function() {
|
|
@@ -30570,6 +30622,19 @@ ${svg}
|
|
|
30570
30622
|
return Dbf.exportRecords(getTable().getRecords(), opts.encoding, opts.field_order);
|
|
30571
30623
|
};
|
|
30572
30624
|
|
|
30625
|
+
// Return the text encoding that exportAsDbf() will use for the current
|
|
30626
|
+
// options. If we're exporting the untouched original DBF bytes, use the
|
|
30627
|
+
// reader's detected/declared encoding; otherwise we regenerate with either
|
|
30628
|
+
// opts.encoding or the writer default (utf8).
|
|
30629
|
+
this.getDbfEncoding = function(optsArg) {
|
|
30630
|
+
var opts = optsArg || {};
|
|
30631
|
+
var useOriginal = !!reader && !altered && !opts.field_order && !opts.encoding;
|
|
30632
|
+
if (useOriginal) {
|
|
30633
|
+
return reader.getEncoding();
|
|
30634
|
+
}
|
|
30635
|
+
return opts.encoding || 'utf8';
|
|
30636
|
+
};
|
|
30637
|
+
|
|
30573
30638
|
this.getReadOnlyRecordAt = function(i) {
|
|
30574
30639
|
return reader ? reader.readRow(i) : table.getReadOnlyRecordAt(i);
|
|
30575
30640
|
};
|
|
@@ -31409,7 +31474,7 @@ ${svg}
|
|
|
31409
31474
|
(srcCollection.features || srcCollection.geometries || []).forEach(importer.parseObject);
|
|
31410
31475
|
dataset = importer.done();
|
|
31411
31476
|
importCRS(dataset, srcObj); // TODO: remove this
|
|
31412
|
-
warnIfProjectedCoords(dataset, srcObj);
|
|
31477
|
+
warnIfProjectedCoords(dataset, srcObj, opts);
|
|
31413
31478
|
return dataset;
|
|
31414
31479
|
}
|
|
31415
31480
|
|
|
@@ -31417,12 +31482,13 @@ ${svg}
|
|
|
31417
31482
|
// `crs` member). If the imported file makes no CRS claim but its coordinates
|
|
31418
31483
|
// are clearly outside lat-long range, warn the user: silent fallthrough here
|
|
31419
31484
|
// usually surfaces later as cryptic -proj errors or grossly wrong output.
|
|
31420
|
-
function warnIfProjectedCoords(dataset, jsonObj) {
|
|
31485
|
+
function warnIfProjectedCoords(dataset, jsonObj, opts) {
|
|
31486
|
+
if (!opts.warn_projected_coords) return;
|
|
31421
31487
|
if (jsonObj && jsonObj.crs) return; // user has explicitly declared a CRS
|
|
31422
31488
|
var bounds = getRoughDatasetBounds(dataset);
|
|
31423
31489
|
if (!bounds || !bounds.hasBounds()) return;
|
|
31424
31490
|
if (probablyDecimalDegreeBounds(bounds)) return;
|
|
31425
|
-
warn('Imported GeoJSON has coordinates outside the lat-long range
|
|
31491
|
+
warn('Imported GeoJSON has coordinates outside the lat-long range -- ' +
|
|
31426
31492
|
' importing as projected geometry with unknown CRS. Commands ' +
|
|
31427
31493
|
'like -proj that require a CRS will not work until you set a source ' +
|
|
31428
31494
|
'CRS, e.g. -proj init=EPSG:3857.');
|
|
@@ -32485,7 +32551,7 @@ ${svg}
|
|
|
32485
32551
|
if (fmt == 'topojson') {
|
|
32486
32552
|
retn.dataset = importTopoJSON(content, opts);
|
|
32487
32553
|
} else if (fmt == 'geojson') {
|
|
32488
|
-
retn.dataset = importGeoJSON(content, opts);
|
|
32554
|
+
retn.dataset = importGeoJSON(content, getGeoJSONImportOpts(opts));
|
|
32489
32555
|
} else if (fmt == 'json') {
|
|
32490
32556
|
retn.dataset = importJSONTable(content);
|
|
32491
32557
|
} else {
|
|
@@ -32497,6 +32563,12 @@ ${svg}
|
|
|
32497
32563
|
return retn;
|
|
32498
32564
|
}
|
|
32499
32565
|
|
|
32566
|
+
function getGeoJSONImportOpts(opts) {
|
|
32567
|
+
return Object.assign({}, opts, {
|
|
32568
|
+
warn_projected_coords: true
|
|
32569
|
+
});
|
|
32570
|
+
}
|
|
32571
|
+
|
|
32500
32572
|
// path: path from top-level to the target object
|
|
32501
32573
|
function selectFromObject(o, path) {
|
|
32502
32574
|
var arrayRxp = /(.*)\[([0-9]+)\]$/; // array bracket notation w/ index
|
|
@@ -43429,20 +43501,24 @@ ${svg}
|
|
|
43429
43501
|
}
|
|
43430
43502
|
}
|
|
43431
43503
|
|
|
43432
|
-
|
|
43433
|
-
|
|
43434
|
-
|
|
43435
|
-
|
|
43436
|
-
|
|
43437
|
-
|
|
43438
|
-
|
|
43439
|
-
|
|
43440
|
-
|
|
43441
|
-
|
|
43442
|
-
|
|
43443
|
-
|
|
43444
|
-
|
|
43445
|
-
|
|
43504
|
+
// Opt-in summary logging. Some commands (e.g. -divide) reuse this join
|
|
43505
|
+
// helper internally and don't want user-facing join diagnostics.
|
|
43506
|
+
if (opts.show_join_message) {
|
|
43507
|
+
printJoinMessage({
|
|
43508
|
+
matches: matchCount,
|
|
43509
|
+
n: n,
|
|
43510
|
+
joins: countJoins(joinCounts),
|
|
43511
|
+
m: srcRecords.length,
|
|
43512
|
+
skipped: skipCount,
|
|
43513
|
+
collisions: collisionCount,
|
|
43514
|
+
collisionFields: collisionFields,
|
|
43515
|
+
destKey: destKey,
|
|
43516
|
+
srcKey: srcKey,
|
|
43517
|
+
unmatchedTargetKeys: takeSampleKeys(unmatchedTargetKeys),
|
|
43518
|
+
unusedSourceKeys: takeSampleKeys(unusedSourceKeys),
|
|
43519
|
+
opts: opts
|
|
43520
|
+
});
|
|
43521
|
+
}
|
|
43446
43522
|
|
|
43447
43523
|
if (opts.unjoined) {
|
|
43448
43524
|
retn.unjoined = {
|
|
@@ -46804,7 +46880,7 @@ ${svg}
|
|
|
46804
46880
|
// Works for lcc, aea, tmerc, etc.
|
|
46805
46881
|
// TODO: add more projections
|
|
46806
46882
|
//
|
|
46807
|
-
function expandProjDefn(str, dataset) {
|
|
46883
|
+
function expandProjDefn(str, dataset, targetLayers) {
|
|
46808
46884
|
var mproj = require$1('mproj');
|
|
46809
46885
|
var proj4, params, bbox, isConic2SP, isCentered, decimals;
|
|
46810
46886
|
if (str in mproj.internal.pj_list === false) {
|
|
@@ -46815,7 +46891,7 @@ ${svg}
|
|
|
46815
46891
|
isCentered = ['tmerc', 'etmerc'].includes(str);
|
|
46816
46892
|
proj4 = '+proj=' + str;
|
|
46817
46893
|
if (isConic2SP || isCentered) {
|
|
46818
|
-
bbox = getBBox(dataset); // TODO: support projected datasets
|
|
46894
|
+
bbox = getBBox(dataset, targetLayers); // TODO: support projected datasets
|
|
46819
46895
|
decimals = getBoundsPrecisionForDisplay(bbox);
|
|
46820
46896
|
params = isCentered ? getCenterParams(bbox, decimals) : getConicParams(bbox, decimals);
|
|
46821
46897
|
proj4 += ' ' + params;
|
|
@@ -46824,11 +46900,16 @@ ${svg}
|
|
|
46824
46900
|
return proj4;
|
|
46825
46901
|
}
|
|
46826
46902
|
|
|
46827
|
-
function getBBox(dataset) {
|
|
46903
|
+
function getBBox(dataset, targetLayers) {
|
|
46904
|
+
var source = targetLayers && targetLayers.length > 0 ? {
|
|
46905
|
+
arcs: dataset.arcs,
|
|
46906
|
+
layers: targetLayers,
|
|
46907
|
+
info: dataset.info
|
|
46908
|
+
} : dataset;
|
|
46828
46909
|
if (!isLatLngCRS(getDatasetCRS(dataset))) {
|
|
46829
46910
|
stop$1('Expected unprojected data');
|
|
46830
46911
|
}
|
|
46831
|
-
return getDatasetBounds(
|
|
46912
|
+
return getDatasetBounds(source).toArray();
|
|
46832
46913
|
}
|
|
46833
46914
|
|
|
46834
46915
|
// See: Savric & Jenny, "Automating the selection of standard parallels for conic map projections"
|
|
@@ -46854,8 +46935,9 @@ ${svg}
|
|
|
46854
46935
|
getConicParams: getConicParams
|
|
46855
46936
|
});
|
|
46856
46937
|
|
|
46857
|
-
cmd.proj = function(dataset, catalog, opts) {
|
|
46938
|
+
cmd.proj = function(dataset, catalog, opts, targetLayers) {
|
|
46858
46939
|
var srcInfo, destInfo, destStr;
|
|
46940
|
+
var implicitlyProjectedNames = getImplicitlyTargetedLayerNames(dataset, targetLayers, layerHasGeometry);
|
|
46859
46941
|
if (opts.init) {
|
|
46860
46942
|
srcInfo = fetchCrsInfo(opts.init, catalog);
|
|
46861
46943
|
if (!srcInfo.crs) stop$1("Unknown projection source:", opts.init);
|
|
@@ -46864,11 +46946,17 @@ ${svg}
|
|
|
46864
46946
|
if (opts.match) {
|
|
46865
46947
|
destInfo = fetchCrsInfo(opts.match, catalog);
|
|
46866
46948
|
} else if (opts.crs) {
|
|
46867
|
-
destStr = expandProjDefn(opts.crs, dataset);
|
|
46949
|
+
destStr = expandProjDefn(opts.crs, dataset, targetLayers);
|
|
46868
46950
|
destInfo = getCrsInfo(destStr);
|
|
46869
46951
|
}
|
|
46870
46952
|
if (destInfo) {
|
|
46871
|
-
projCmd(dataset, destInfo, opts);
|
|
46953
|
+
var didProject = projCmd(dataset, destInfo, opts);
|
|
46954
|
+
if (didProject && implicitlyProjectedNames.length > 0) {
|
|
46955
|
+
message(
|
|
46956
|
+
'Also projected non-target layer' + utils.pluralSuffix(implicitlyProjectedNames.length) +
|
|
46957
|
+
' from the same dataset: ' + implicitlyProjectedNames.join(', ')
|
|
46958
|
+
);
|
|
46959
|
+
}
|
|
46872
46960
|
}
|
|
46873
46961
|
};
|
|
46874
46962
|
|
|
@@ -46886,7 +46974,7 @@ ${svg}
|
|
|
46886
46974
|
if (!datasetHasGeometry(dataset)) {
|
|
46887
46975
|
// still set the crs of datasets that are missing geometry
|
|
46888
46976
|
setDatasetCrsInfo(dataset, destInfo);
|
|
46889
|
-
return;
|
|
46977
|
+
return false;
|
|
46890
46978
|
}
|
|
46891
46979
|
|
|
46892
46980
|
var srcInfo = getDatasetCrsInfo(dataset);
|
|
@@ -46896,7 +46984,7 @@ ${svg}
|
|
|
46896
46984
|
|
|
46897
46985
|
if (crsAreEqual(srcInfo.crs, destInfo.crs)) {
|
|
46898
46986
|
message("Source and destination CRS are the same");
|
|
46899
|
-
return;
|
|
46987
|
+
return false;
|
|
46900
46988
|
}
|
|
46901
46989
|
|
|
46902
46990
|
if (dataset.arcs) {
|
|
@@ -46922,9 +47010,9 @@ ${svg}
|
|
|
46922
47010
|
// replace original layers with modified layers
|
|
46923
47011
|
utils.extend(lyr, target.layers[i]);
|
|
46924
47012
|
});
|
|
47013
|
+
return true;
|
|
46925
47014
|
}
|
|
46926
47015
|
|
|
46927
|
-
|
|
46928
47016
|
// name: a layer identifier, .prj file or projection defn
|
|
46929
47017
|
// Converts layer ids and .prj files to CRS defn
|
|
46930
47018
|
// Returns projection defn
|
|
@@ -48477,6 +48565,9 @@ ${svg}
|
|
|
48477
48565
|
}
|
|
48478
48566
|
|
|
48479
48567
|
cmd.join = function(targetLyr, targetDataset, src, opts) {
|
|
48568
|
+
// Opt in to the post-join summary emitted by joinTableToLayer().
|
|
48569
|
+
// Other commands can reuse the helper without showing this message.
|
|
48570
|
+
opts = Object.assign({}, opts, {show_join_message: true});
|
|
48480
48571
|
var srcType, targetType, retn;
|
|
48481
48572
|
if (!src || !src.dataset) {
|
|
48482
48573
|
stop$1("Missing a joinable data source");
|
|
@@ -51094,8 +51185,9 @@ ${svg}
|
|
|
51094
51185
|
replaceInArray: replaceInArray
|
|
51095
51186
|
});
|
|
51096
51187
|
|
|
51097
|
-
cmd.simplify = function(dataset, opts) {
|
|
51188
|
+
cmd.simplify = function(dataset, opts, targetLayers) {
|
|
51098
51189
|
var arcs = dataset.arcs;
|
|
51190
|
+
var implicitlySimplifiedNames = getImplicitlyTargetedLayerNames(dataset, targetLayers, layerHasPaths);
|
|
51099
51191
|
if (!arcs || arcs.size() === 0) return; // removed in v0.4.125: stop("Missing path data");
|
|
51100
51192
|
opts = getStandardSimplifyOpts(dataset, opts); // standardize options
|
|
51101
51193
|
simplifyPaths(arcs, opts);
|
|
@@ -51114,6 +51206,12 @@ ${svg}
|
|
|
51114
51206
|
}
|
|
51115
51207
|
|
|
51116
51208
|
finalizeSimplification(dataset, opts);
|
|
51209
|
+
if (implicitlySimplifiedNames.length > 0) {
|
|
51210
|
+
message(
|
|
51211
|
+
'Also simplified non-target layer' + utils.pluralSuffix(implicitlySimplifiedNames.length) +
|
|
51212
|
+
' from the same dataset: ' + implicitlySimplifiedNames.join(', ')
|
|
51213
|
+
);
|
|
51214
|
+
}
|
|
51117
51215
|
};
|
|
51118
51216
|
|
|
51119
51217
|
function finalizeSimplification(dataset, opts) {
|
|
@@ -52807,7 +52905,7 @@ ${svg}
|
|
|
52807
52905
|
await initProjLibrary(opts);
|
|
52808
52906
|
job.resumeCommand();
|
|
52809
52907
|
targets.forEach(function(targ) {
|
|
52810
|
-
cmd.proj(targ.dataset, job.catalog, opts);
|
|
52908
|
+
cmd.proj(targ.dataset, job.catalog, opts, targ.layers);
|
|
52811
52909
|
});
|
|
52812
52910
|
|
|
52813
52911
|
} else if (name == 'rectangle') {
|
|
@@ -52850,7 +52948,7 @@ ${svg}
|
|
|
52850
52948
|
if (opts.variable) {
|
|
52851
52949
|
cmd.variableSimplify(targetLayers, targetDataset, opts);
|
|
52852
52950
|
} else {
|
|
52853
|
-
cmd.simplify(targetDataset, opts);
|
|
52951
|
+
cmd.simplify(targetDataset, opts, targetLayers);
|
|
52854
52952
|
}
|
|
52855
52953
|
|
|
52856
52954
|
} else if (name == 'slice') {
|
|
@@ -52976,7 +53074,7 @@ ${svg}
|
|
|
52976
53074
|
});
|
|
52977
53075
|
}
|
|
52978
53076
|
|
|
52979
|
-
var version = "0.7.
|
|
53077
|
+
var version = "0.7.6";
|
|
52980
53078
|
|
|
52981
53079
|
// Parse command line args into commands and run them
|
|
52982
53080
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|