mapshaper 0.7.7 → 0.7.9
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 +994 -56
- package/package.json +7 -3
- package/www/ai-config.js +62 -0
- package/www/geoparquet.js +14311 -0
- package/www/index.html +2 -2
- package/www/mapshaper-gui.js +162 -3
- package/www/mapshaper.js +994 -56
- package/www/modules.js +13695 -11919
- package/www/sponsor.html +4 -4
package/mapshaper.js
CHANGED
|
@@ -4879,7 +4879,7 @@
|
|
|
4879
4879
|
this.ty -= cy * (sy - 1);
|
|
4880
4880
|
};
|
|
4881
4881
|
|
|
4882
|
-
var mproj$
|
|
4882
|
+
var mproj$2 = require$1('mproj');
|
|
4883
4883
|
|
|
4884
4884
|
// Constructor function for a compound projection consisting of a default
|
|
4885
4885
|
// projection and one or more rectangular frames that are projected separately
|
|
@@ -4893,7 +4893,7 @@
|
|
|
4893
4893
|
var mainFrame = initFrame(mainParams);
|
|
4894
4894
|
var mainP = mainFrame.crs;
|
|
4895
4895
|
var frames = [mainFrame];
|
|
4896
|
-
var mixedP = initMixedProjection(mproj$
|
|
4896
|
+
var mixedP = initMixedProjection(mproj$2);
|
|
4897
4897
|
|
|
4898
4898
|
// This CRS masquerades as the main projection... the version with
|
|
4899
4899
|
// custom insets is exposed to savvy users
|
|
@@ -4937,7 +4937,7 @@
|
|
|
4937
4937
|
function initFrame(params) {
|
|
4938
4938
|
return {
|
|
4939
4939
|
bounds: new Bounds(bboxToRadians(params.bbox)),
|
|
4940
|
-
crs: mproj$
|
|
4940
|
+
crs: mproj$2.pj_init(params.proj)
|
|
4941
4941
|
};
|
|
4942
4942
|
}
|
|
4943
4943
|
|
|
@@ -4949,7 +4949,7 @@
|
|
|
4949
4949
|
}
|
|
4950
4950
|
|
|
4951
4951
|
function projectFrameOrigin(origin, P) {
|
|
4952
|
-
var xy = mproj$
|
|
4952
|
+
var xy = mproj$2.pj_fwd_deg({lam: origin[0], phi: origin[1]}, P);
|
|
4953
4953
|
return [xy.x, xy.y];
|
|
4954
4954
|
}
|
|
4955
4955
|
|
|
@@ -4958,7 +4958,7 @@
|
|
|
4958
4958
|
for (var i=0, n=frames.length; i<n; i++) {
|
|
4959
4959
|
frame = frames[i];
|
|
4960
4960
|
if (frame.bounds.containsPoint(lp.lam, lp.phi)) {
|
|
4961
|
-
xy2 = mproj$
|
|
4961
|
+
xy2 = mproj$2.pj_fwd(lp, frame.crs);
|
|
4962
4962
|
if (frame.matrix) {
|
|
4963
4963
|
frame.matrix.transformXY(xy2.x, xy2.y, xy2);
|
|
4964
4964
|
}
|
|
@@ -5161,7 +5161,7 @@
|
|
|
5161
5161
|
probablyDecimalDegreeBounds: probablyDecimalDegreeBounds
|
|
5162
5162
|
});
|
|
5163
5163
|
|
|
5164
|
-
var mproj = require$1('mproj');
|
|
5164
|
+
var mproj$1 = require$1('mproj');
|
|
5165
5165
|
|
|
5166
5166
|
var asyncLoader = null;
|
|
5167
5167
|
|
|
@@ -5202,7 +5202,7 @@
|
|
|
5202
5202
|
else if (x > 180) x = 180;
|
|
5203
5203
|
}
|
|
5204
5204
|
xy = [x, y];
|
|
5205
|
-
mproj.pj_transform_point(src, dest, xy);
|
|
5205
|
+
mproj$1.pj_transform_point(src, dest, xy);
|
|
5206
5206
|
return xy;
|
|
5207
5207
|
};
|
|
5208
5208
|
}
|
|
@@ -5212,8 +5212,8 @@
|
|
|
5212
5212
|
function getProjTransform2(src, dest) {
|
|
5213
5213
|
var xx = [0],
|
|
5214
5214
|
yy = [0],
|
|
5215
|
-
preK = src.is_latlong ? mproj.internal.DEG_TO_RAD : 1,
|
|
5216
|
-
postK = dest.is_latlong ? mproj.internal.RAD_TO_DEG : 1,
|
|
5215
|
+
preK = src.is_latlong ? mproj$1.internal.DEG_TO_RAD : 1,
|
|
5216
|
+
postK = dest.is_latlong ? mproj$1.internal.RAD_TO_DEG : 1,
|
|
5217
5217
|
clampSrc = isLatLngCRS(src);
|
|
5218
5218
|
|
|
5219
5219
|
return function(x, y) {
|
|
@@ -5227,7 +5227,7 @@
|
|
|
5227
5227
|
yy[0] = y * preK;
|
|
5228
5228
|
try {
|
|
5229
5229
|
dest = dest.__mixed_crs || dest;
|
|
5230
|
-
mproj.pj_transform(src, dest, xx, yy);
|
|
5230
|
+
mproj$1.pj_transform(src, dest, xx, yy);
|
|
5231
5231
|
fail = xx[0] == Infinity; // mproj invalid coord value
|
|
5232
5232
|
} catch(e) {
|
|
5233
5233
|
fail = true;
|
|
@@ -5258,19 +5258,29 @@
|
|
|
5258
5258
|
}
|
|
5259
5259
|
|
|
5260
5260
|
function crsToProj4(P) {
|
|
5261
|
-
return mproj.internal.get_proj_defn(P);
|
|
5261
|
+
return mproj$1.internal.get_proj_defn(P);
|
|
5262
5262
|
}
|
|
5263
5263
|
|
|
5264
5264
|
function crsToPrj(P) {
|
|
5265
5265
|
var wkt;
|
|
5266
5266
|
try {
|
|
5267
|
-
wkt = mproj.internal.wkt_from_proj4(P);
|
|
5267
|
+
wkt = mproj$1.internal.wkt_from_proj4(P);
|
|
5268
5268
|
} catch(e) {
|
|
5269
5269
|
// console.log(e)
|
|
5270
5270
|
}
|
|
5271
5271
|
return wkt;
|
|
5272
5272
|
}
|
|
5273
5273
|
|
|
5274
|
+
function crsToWkt2(P) {
|
|
5275
|
+
var wkt;
|
|
5276
|
+
try {
|
|
5277
|
+
wkt = mproj$1.internal.wkt2_from_proj4(P);
|
|
5278
|
+
} catch(e) {
|
|
5279
|
+
// WKT2 export may be unavailable for some custom definitions.
|
|
5280
|
+
}
|
|
5281
|
+
return wkt;
|
|
5282
|
+
}
|
|
5283
|
+
|
|
5274
5284
|
function crsAreEqual(a, b) {
|
|
5275
5285
|
var str = crsToProj4(a);
|
|
5276
5286
|
return !!str && str == crsToProj4(b);
|
|
@@ -5287,7 +5297,7 @@
|
|
|
5287
5297
|
var defn;
|
|
5288
5298
|
// prepend '+proj=' to bare proj names
|
|
5289
5299
|
str = str.replace(/(^| )([\w]+)($| )/, function(a, b, c, d) {
|
|
5290
|
-
if (c in mproj.internal.pj_list) {
|
|
5300
|
+
if (c in mproj$1.internal.pj_list) {
|
|
5291
5301
|
return b + '+proj=' + c + d;
|
|
5292
5302
|
}
|
|
5293
5303
|
return a;
|
|
@@ -5335,7 +5345,7 @@
|
|
|
5335
5345
|
P = defn;
|
|
5336
5346
|
} else {
|
|
5337
5347
|
try {
|
|
5338
|
-
P = mproj.pj_init(defn);
|
|
5348
|
+
P = mproj$1.pj_init(defn);
|
|
5339
5349
|
} catch(e) {
|
|
5340
5350
|
stop$1('Unable to use projection', defn, '(' + e.message + ')');
|
|
5341
5351
|
}
|
|
@@ -5399,8 +5409,8 @@
|
|
|
5399
5409
|
// Returns k, the ratio of coordinate distance to distance on the ground
|
|
5400
5410
|
function getScaleFactorAtXY(x, y, crs) {
|
|
5401
5411
|
var dist = 1 / crs.to_meter;
|
|
5402
|
-
var lp = mproj.pj_inv_deg({x: x, y: y}, crs);
|
|
5403
|
-
var lp2 = mproj.pj_inv_deg({x: x + dist, y: y}, crs);
|
|
5412
|
+
var lp = mproj$1.pj_inv_deg({x: x, y: y}, crs);
|
|
5413
|
+
var lp2 = mproj$1.pj_inv_deg({x: x + dist, y: y}, crs);
|
|
5404
5414
|
var k = 1 / geom.greatCircleDistance(lp.lam, lp.phi, lp2.lam, lp2.phi);
|
|
5405
5415
|
return k;
|
|
5406
5416
|
}
|
|
@@ -5438,7 +5448,7 @@
|
|
|
5438
5448
|
}
|
|
5439
5449
|
|
|
5440
5450
|
function printProjections() {
|
|
5441
|
-
var index = mproj.internal.pj_list;
|
|
5451
|
+
var index = mproj$1.internal.pj_list;
|
|
5442
5452
|
var msg = 'Proj4 projections\n';
|
|
5443
5453
|
Object.keys(index).sort().forEach(function(id) {
|
|
5444
5454
|
msg += ' ' + utils.rpad(id, 7, ' ') + ' ' + index[id].name + '\n';
|
|
@@ -5453,18 +5463,46 @@
|
|
|
5453
5463
|
function wkt1ToProj(str) {
|
|
5454
5464
|
var proj4;
|
|
5455
5465
|
try {
|
|
5456
|
-
proj4 = mproj.internal.wkt_to_proj4(str);
|
|
5466
|
+
proj4 = mproj$1.internal.wkt_to_proj4(str);
|
|
5457
5467
|
} catch(e) {
|
|
5458
5468
|
stop$1('Unusable .prj file (' + e.message + ')');
|
|
5459
5469
|
}
|
|
5460
5470
|
return proj4;
|
|
5461
5471
|
}
|
|
5462
5472
|
|
|
5473
|
+
function wkt2ToProj(str) {
|
|
5474
|
+
var proj4;
|
|
5475
|
+
try {
|
|
5476
|
+
proj4 = mproj$1.internal.wkt2_to_proj4(str);
|
|
5477
|
+
} catch(e) {
|
|
5478
|
+
stop$1('Unusable WKT2 CRS (' + e.message + ')');
|
|
5479
|
+
}
|
|
5480
|
+
return proj4;
|
|
5481
|
+
}
|
|
5482
|
+
|
|
5483
|
+
function wktToProj(str) {
|
|
5484
|
+
var proj4;
|
|
5485
|
+
try {
|
|
5486
|
+
proj4 = mproj$1.internal.wkt2_to_proj4(str);
|
|
5487
|
+
} catch(e) {
|
|
5488
|
+
try {
|
|
5489
|
+
proj4 = mproj$1.internal.wkt_to_proj4(str);
|
|
5490
|
+
} catch(e2) {
|
|
5491
|
+
stop$1('Unusable WKT CRS (' + e2.message + ')');
|
|
5492
|
+
}
|
|
5493
|
+
}
|
|
5494
|
+
return proj4;
|
|
5495
|
+
}
|
|
5496
|
+
|
|
5463
5497
|
// Convert contents of a .prj file to a projection object
|
|
5464
5498
|
function parsePrj(str) {
|
|
5465
5499
|
return parseCrsString$1(wkt1ToProj(str));
|
|
5466
5500
|
}
|
|
5467
5501
|
|
|
5502
|
+
function parseWkt(str) {
|
|
5503
|
+
return parseCrsString$1(wktToProj(str));
|
|
5504
|
+
}
|
|
5505
|
+
|
|
5468
5506
|
// Extract an EPSG (or other authority) code from a short string like
|
|
5469
5507
|
// "epsg:4326" or "ESRI:54030". Returns {org, code} or null.
|
|
5470
5508
|
function parseAuthorityCodeString(str) {
|
|
@@ -5522,6 +5560,7 @@
|
|
|
5522
5560
|
crsAreEqual: crsAreEqual,
|
|
5523
5561
|
crsToPrj: crsToPrj,
|
|
5524
5562
|
crsToProj4: crsToProj4,
|
|
5563
|
+
crsToWkt2: crsToWkt2,
|
|
5525
5564
|
findProjLibs: findProjLibs,
|
|
5526
5565
|
getCrsInfo: getCrsInfo,
|
|
5527
5566
|
getDatasetCRS: getDatasetCRS,
|
|
@@ -5544,6 +5583,7 @@
|
|
|
5544
5583
|
parseAuthorityCodeString: parseAuthorityCodeString,
|
|
5545
5584
|
parseCrsString: parseCrsString$1,
|
|
5546
5585
|
parsePrj: parsePrj,
|
|
5586
|
+
parseWkt: parseWkt,
|
|
5547
5587
|
printProjections: printProjections,
|
|
5548
5588
|
projectPoint: projectPoint,
|
|
5549
5589
|
requireDatasetsHaveCompatibleCRS: requireDatasetsHaveCompatibleCRS,
|
|
@@ -5551,7 +5591,9 @@
|
|
|
5551
5591
|
setDatasetCrsInfo: setDatasetCrsInfo,
|
|
5552
5592
|
setProjectionLoader: setProjectionLoader,
|
|
5553
5593
|
toLngLat: toLngLat,
|
|
5554
|
-
wkt1ToProj: wkt1ToProj
|
|
5594
|
+
wkt1ToProj: wkt1ToProj,
|
|
5595
|
+
wkt2ToProj: wkt2ToProj,
|
|
5596
|
+
wktToProj: wktToProj
|
|
5555
5597
|
});
|
|
5556
5598
|
|
|
5557
5599
|
// Coordinate iterators
|
|
@@ -8024,6 +8066,8 @@
|
|
|
8024
8066
|
type = null;
|
|
8025
8067
|
if (ext == 'dbf' || ext == 'shp' || ext == 'kml' || ext == 'svg' || ext == 'fgb' || ext == 'gpkg') {
|
|
8026
8068
|
type = ext;
|
|
8069
|
+
} else if (ext == 'parquet' || ext == 'geoparquet') {
|
|
8070
|
+
type = 'parquet';
|
|
8027
8071
|
} else if (isAuxiliaryInputFileType(ext)) {
|
|
8028
8072
|
type = ext;
|
|
8029
8073
|
} else if (/json$/.test(ext)) { // matches topojson, geojson, json
|
|
@@ -8165,7 +8209,7 @@
|
|
|
8165
8209
|
function isSupportedBinaryInputType(path) {
|
|
8166
8210
|
var ext = getFileExtension(path).toLowerCase();
|
|
8167
8211
|
return ext == 'shp' || ext == 'shx' || ext == 'dbf' ||
|
|
8168
|
-
ext == 'fgb' || ext == 'gpkg' || ext == PACKAGE_EXT; // GUI also supports zip files
|
|
8212
|
+
ext == 'fgb' || ext == 'gpkg' || ext == 'parquet' || ext == 'geoparquet' || ext == PACKAGE_EXT; // GUI also supports zip files
|
|
8169
8213
|
}
|
|
8170
8214
|
|
|
8171
8215
|
function isImportableAsBinary(path) {
|
|
@@ -24748,11 +24792,7 @@ ${svg}
|
|
|
24748
24792
|
}); });
|
|
24749
24793
|
}
|
|
24750
24794
|
|
|
24751
|
-
function
|
|
24752
|
-
|
|
24753
|
-
function buildHeader(t,r=0){let n,o=new Builder,i=0;t.columns&&(i=Header.createColumnsVector(o,t.columns.map(e=>{let t;return t=o.createString(e.name),Column.startColumn(o),Column.addName(o,t),Column.addType(o,e.type),Column.endColumn(o)})));let f=o.createString("L1");r&&(Crs.startCrs(o),Crs.addCode(o,r),n=Crs.endCrs(o)),Header.startHeader(o),n&&Header.addCrs(o,n),Header.addFeaturesCount(o,BigInt(t.featuresCount)),Header.addGeometryType(o,t.geometryType),Header.addIndexNodeSize(o,0),i&&Header.addColumns(o,i),Header.addName(o,f);let u=Header.endHeader(o);return o.finishSizePrefixed(u),o.asUint8Array()}function mapColumn(e,t){return {name:t,type:function(e){if("boolean"==typeof e)return ColumnType.Bool;if("number"==typeof e)return ColumnType.Double;if("string"==typeof e||null===e)return ColumnType.String;if(e instanceof Uint8Array)return ColumnType.Binary;if("object"==typeof e)return ColumnType.Json;throw Error(`Unknown type (value '${e}')`)}(e[t]),title:null,description:null,width:-1,precision:-1,scale:-1,nullable:true,unique:false,primary_key:false}}
|
|
24754
|
-
|
|
24755
|
-
function serialize(i,l=0){var n;let a,p,f=(a=(n=i).features[0].properties,p=null,a&&(p=Object.keys(a).map(e=>mapColumn(a,e))),{geometryType:inferGeometryType(n.features),columns:p,featuresCount:n.features.length}),c=buildHeader(f,l),g=i.features.map(e=>buildFeature("GeometryCollection"===e.geometry.type?parseGC(e.geometry):parseGeometry(e.geometry),e.properties,f)),d=g.map(e=>e.length).reduce((e,t)=>e+t),y=new Uint8Array(magicbytes.length+c.length+d);y.set(c,magicbytes.length);let h=magicbytes.length+c.length;for(let e of g)y.set(e,h),h+=e.length;return y.set(magicbytes),y}
|
|
24795
|
+
function buildHeader(t,r=0){let n,o=new Builder,i=0;t.columns&&(i=Header.createColumnsVector(o,t.columns.map(e=>{let t;return t=o.createString(e.name),Column.startColumn(o),Column.addName(o,t),Column.addType(o,e.type),Column.endColumn(o)})));let f=o.createString("L1");r&&(Crs.startCrs(o),Crs.addCode(o,r),n=Crs.endCrs(o)),Header.startHeader(o),n&&Header.addCrs(o,n),Header.addFeaturesCount(o,BigInt(t.featuresCount)),Header.addGeometryType(o,t.geometryType),Header.addIndexNodeSize(o,0),i&&Header.addColumns(o,i),Header.addName(o,f);let u=Header.endHeader(o);return o.finishSizePrefixed(u),o.asUint8Array()}
|
|
24756
24796
|
|
|
24757
24797
|
// bytes: Uint8Array
|
|
24758
24798
|
function getHeaderMeta(bytes) {
|
|
@@ -24788,6 +24828,7 @@ ${svg}
|
|
|
24788
24828
|
bb.setPosition(offset);
|
|
24789
24829
|
var feature = Feature.getSizePrefixedRootAsFeature(bb);
|
|
24790
24830
|
geojsonFeature = fromFeature(id++, feature, headerMeta);
|
|
24831
|
+
delete geojsonFeature.id;
|
|
24791
24832
|
offset += SIZE_PREFIX_LEN + featureLength;
|
|
24792
24833
|
return geojsonFeature;
|
|
24793
24834
|
};
|
|
@@ -24817,6 +24858,66 @@ ${svg}
|
|
|
24817
24858
|
return builder.asUint8Array();
|
|
24818
24859
|
}
|
|
24819
24860
|
|
|
24861
|
+
function serializeWithColumns(geojson, columns) {
|
|
24862
|
+
var headerMeta = {
|
|
24863
|
+
geometryType: inferGeometryType(geojson.features),
|
|
24864
|
+
columns: columns,
|
|
24865
|
+
featuresCount: geojson.features.length};
|
|
24866
|
+
var header = buildHeader(headerMeta);
|
|
24867
|
+
var features = geojson.features.map(function(feature) {
|
|
24868
|
+
var geometry = feature.geometry.type == 'GeometryCollection' ?
|
|
24869
|
+
parseGC(feature.geometry) :
|
|
24870
|
+
parseGeometry(feature.geometry);
|
|
24871
|
+
omitRedundantGeometryType(geometry, headerMeta.geometryType);
|
|
24872
|
+
return buildFeature(geometry, normalizeProperties(feature.properties, columns), headerMeta);
|
|
24873
|
+
});
|
|
24874
|
+
var featureBytes = features.reduce(function(sum, feature) {
|
|
24875
|
+
return sum + feature.length;
|
|
24876
|
+
}, 0);
|
|
24877
|
+
var output = new Uint8Array(magicbytes.length + header.length + featureBytes);
|
|
24878
|
+
var offset = magicbytes.length;
|
|
24879
|
+
output.set(header, offset);
|
|
24880
|
+
offset += header.length;
|
|
24881
|
+
features.forEach(function(feature) {
|
|
24882
|
+
output.set(feature, offset);
|
|
24883
|
+
offset += feature.length;
|
|
24884
|
+
});
|
|
24885
|
+
output.set(magicbytes);
|
|
24886
|
+
return output;
|
|
24887
|
+
}
|
|
24888
|
+
|
|
24889
|
+
function omitRedundantGeometryType(geometry, headerType) {
|
|
24890
|
+
if (headerType != GeometryType.Unknown && geometry.type == headerType) {
|
|
24891
|
+
geometry.type = GeometryType.Unknown;
|
|
24892
|
+
}
|
|
24893
|
+
}
|
|
24894
|
+
|
|
24895
|
+
function inferGeometryType(features) {
|
|
24896
|
+
var type;
|
|
24897
|
+
features.forEach(function(feature) {
|
|
24898
|
+
var next = GeometryType[feature.geometry.type] || GeometryType.Unknown;
|
|
24899
|
+
if (type === undefined) {
|
|
24900
|
+
type = next;
|
|
24901
|
+
} else if (type != next) {
|
|
24902
|
+
type = GeometryType.Unknown;
|
|
24903
|
+
}
|
|
24904
|
+
});
|
|
24905
|
+
if (type === undefined) {
|
|
24906
|
+
throw new Error('Could not infer geometry type for collection of features.');
|
|
24907
|
+
}
|
|
24908
|
+
return type;
|
|
24909
|
+
}
|
|
24910
|
+
|
|
24911
|
+
function normalizeProperties(properties, columns) {
|
|
24912
|
+
var copy = {};
|
|
24913
|
+
properties = properties || {};
|
|
24914
|
+
columns.forEach(function(column) {
|
|
24915
|
+
var val = properties[column.name];
|
|
24916
|
+
copy[column.name] = val === undefined ? null : val;
|
|
24917
|
+
});
|
|
24918
|
+
return copy;
|
|
24919
|
+
}
|
|
24920
|
+
|
|
24820
24921
|
function createColumnsVector(builder, columns) {
|
|
24821
24922
|
if (!columns || columns.length === 0) return 0;
|
|
24822
24923
|
var offsets = columns.map(function(col) {
|
|
@@ -24867,12 +24968,13 @@ ${svg}
|
|
|
24867
24968
|
var crsMeta = resolveOutputCRS(dataset);
|
|
24868
24969
|
return dataset.layers.map(function(lyr) {
|
|
24869
24970
|
var geojson = getFeatureCollection(lyr, dataset, opts);
|
|
24870
|
-
var
|
|
24971
|
+
var columns = getFlatGeobufColumns(lyr);
|
|
24972
|
+
var content = serializeWithColumns(geojson, columns);
|
|
24871
24973
|
var filename = lyr.name + '.' + extension;
|
|
24872
24974
|
if (crsMeta) {
|
|
24873
24975
|
content = rewriteHeaderWithCRS(content, crsMeta);
|
|
24874
24976
|
} else {
|
|
24875
|
-
message('Wrote', filename, 'without a CRS in the FlatGeobuf header (mapshaper could not derive
|
|
24977
|
+
message('Wrote', filename, 'without a CRS in the FlatGeobuf header (mapshaper could not derive CRS metadata for this dataset). Downstream tools may misinterpret the coordinates or refuse to load the file.');
|
|
24876
24978
|
}
|
|
24877
24979
|
return {
|
|
24878
24980
|
content: content,
|
|
@@ -24892,17 +24994,64 @@ ${svg}
|
|
|
24892
24994
|
};
|
|
24893
24995
|
}
|
|
24894
24996
|
|
|
24895
|
-
|
|
24997
|
+
function getFlatGeobufColumns(lyr) {
|
|
24998
|
+
var records = lyr.data ? lyr.data.getRecords() : [];
|
|
24999
|
+
return lyr.data ? lyr.data.getFields().map(function(name) {
|
|
25000
|
+
return {
|
|
25001
|
+
name: name,
|
|
25002
|
+
type: getFlatGeobufColumnType(name, records),
|
|
25003
|
+
title: null,
|
|
25004
|
+
description: null,
|
|
25005
|
+
width: -1,
|
|
25006
|
+
precision: -1,
|
|
25007
|
+
scale: -1,
|
|
25008
|
+
nullable: true,
|
|
25009
|
+
unique: false,
|
|
25010
|
+
primary_key: false
|
|
25011
|
+
};
|
|
25012
|
+
}) : [];
|
|
25013
|
+
}
|
|
25014
|
+
|
|
25015
|
+
function getFlatGeobufColumnType(name, records) {
|
|
25016
|
+
var type = getColumnType(name, records);
|
|
25017
|
+
if (type == 'boolean') return 2; // ColumnType.Bool
|
|
25018
|
+
if (type == 'number') return getFlatGeobufNumberType(name, records);
|
|
25019
|
+
if (type == 'object') return 12; // ColumnType.Json
|
|
25020
|
+
return 11; // ColumnType.String
|
|
25021
|
+
}
|
|
25022
|
+
|
|
25023
|
+
function getFlatGeobufNumberType(name, records) {
|
|
25024
|
+
var min = Infinity;
|
|
25025
|
+
var max = -Infinity;
|
|
25026
|
+
var hasValue = false;
|
|
25027
|
+
var val;
|
|
25028
|
+
for (var i = 0; i < records.length; i++) {
|
|
25029
|
+
val = records[i] ? records[i][name] : null;
|
|
25030
|
+
if (val === null || val === undefined) continue;
|
|
25031
|
+
if (!Number.isFinite(val) || Math.floor(val) !== val) {
|
|
25032
|
+
return 10; // ColumnType.Double
|
|
25033
|
+
}
|
|
25034
|
+
hasValue = true;
|
|
25035
|
+
if (val < min) min = val;
|
|
25036
|
+
if (val > max) max = val;
|
|
25037
|
+
}
|
|
25038
|
+
if (!hasValue) return 10; // ColumnType.Double
|
|
25039
|
+
if (min >= -2147483648 && max <= 2147483647) return 5; // ColumnType.Int
|
|
25040
|
+
if (Number.isSafeInteger(min) && Number.isSafeInteger(max)) return 7; // ColumnType.Long
|
|
25041
|
+
return 10; // ColumnType.Double
|
|
25042
|
+
}
|
|
25043
|
+
|
|
25044
|
+
// Try several strategies to derive CRS metadata for the dataset. Returns
|
|
24896
25045
|
// a CRS-meta object suitable for buildHeaderWithCRS(), or null if no
|
|
24897
|
-
//
|
|
24898
|
-
//
|
|
25046
|
+
// CRS metadata could be found. Prefer authority/code when available, but
|
|
25047
|
+
// also write WKT so custom CRSes can be read by CRS-aware tools.
|
|
24899
25048
|
function resolveOutputCRS(dataset) {
|
|
24900
25049
|
var info = (dataset && dataset.info) || {};
|
|
24901
25050
|
var meta;
|
|
24902
25051
|
|
|
24903
25052
|
// 1. Round-tripped from another FlatGeobuf
|
|
24904
25053
|
meta = normalizeCRS(info.flatgeobuf_crs);
|
|
24905
|
-
if (meta) return meta;
|
|
25054
|
+
if (meta) return addWktToCRS(meta, dataset);
|
|
24906
25055
|
|
|
24907
25056
|
// 2. Round-tripped from a GeoPackage with an EPSG-coded SRS
|
|
24908
25057
|
if (info.geopackage_crs &&
|
|
@@ -24911,16 +25060,16 @@ ${svg}
|
|
|
24911
25060
|
org: 'EPSG',
|
|
24912
25061
|
code: info.geopackage_crs.organization_coordsys_id || info.geopackage_crs.srs_id
|
|
24913
25062
|
});
|
|
24914
|
-
if (meta) return meta;
|
|
25063
|
+
if (meta) return addWktToCRS(meta, dataset);
|
|
24915
25064
|
}
|
|
24916
25065
|
|
|
24917
25066
|
// 3. Explicit "epsg:NNNN" / "esri:NNNN" string set by -proj or alike
|
|
24918
25067
|
meta = normalizeCRS(parseAuthorityCodeString(info.crs_string));
|
|
24919
|
-
if (meta) return meta;
|
|
25068
|
+
if (meta) return addWktToCRS(meta, dataset);
|
|
24920
25069
|
|
|
24921
25070
|
// 4. AUTHORITY["EPSG", N] in a .prj/WKT1 string (typically from a Shapefile)
|
|
24922
25071
|
meta = normalizeCRS(parseAuthorityCodeFromWkt(info.wkt1));
|
|
24923
|
-
if (meta) return meta;
|
|
25072
|
+
if (meta) return addWktToCRS(meta, dataset);
|
|
24924
25073
|
|
|
24925
25074
|
// 5. Recognized CRS object: WGS-84 (any encoding) or Web Mercator.
|
|
24926
25075
|
// getDatasetCrsInfo() also auto-detects WGS-84 from lat/lng-like bounds,
|
|
@@ -24933,36 +25082,65 @@ ${svg}
|
|
|
24933
25082
|
}
|
|
24934
25083
|
if (crsInfo && crsInfo.crs) {
|
|
24935
25084
|
if (isWGS84(crsInfo.crs)) {
|
|
24936
|
-
return normalizeCRS({org: 'EPSG', code: 4326});
|
|
25085
|
+
return addWktToCRS(normalizeCRS({org: 'EPSG', code: 4326}), dataset, crsInfo);
|
|
24937
25086
|
}
|
|
24938
25087
|
if (isWebMercator(crsInfo.crs)) {
|
|
24939
|
-
return normalizeCRS({org: 'EPSG', code: 3857});
|
|
25088
|
+
return addWktToCRS(normalizeCRS({org: 'EPSG', code: 3857}), dataset, crsInfo);
|
|
24940
25089
|
}
|
|
25090
|
+
meta = addWktToCRS({}, dataset, crsInfo);
|
|
25091
|
+
if (meta) return meta;
|
|
24941
25092
|
}
|
|
24942
25093
|
|
|
24943
25094
|
return null;
|
|
24944
25095
|
}
|
|
24945
25096
|
|
|
24946
25097
|
function normalizeCRS(crs) {
|
|
24947
|
-
if (!crs
|
|
25098
|
+
if (!crs) return null;
|
|
24948
25099
|
var code = +crs.code;
|
|
24949
|
-
|
|
24950
|
-
code = Math.round(code);
|
|
25100
|
+
var hasCode = Number.isFinite(code) && code > 0;
|
|
25101
|
+
if (hasCode) code = Math.round(code);
|
|
24951
25102
|
var org = crs.org ? String(crs.org).toUpperCase() : null;
|
|
24952
|
-
if (!org && looksLikeEPSGCode(code)) {
|
|
25103
|
+
if (!org && hasCode && looksLikeEPSGCode(code)) {
|
|
24953
25104
|
org = 'EPSG';
|
|
24954
25105
|
}
|
|
24955
|
-
if (org != 'EPSG') return null;
|
|
25106
|
+
if (hasCode && org != 'EPSG') return null;
|
|
25107
|
+
if (!hasCode && !crs.wkt) return null;
|
|
24956
25108
|
return {
|
|
24957
|
-
org: 'EPSG',
|
|
24958
|
-
code: code,
|
|
25109
|
+
org: hasCode ? 'EPSG' : null,
|
|
25110
|
+
code: hasCode ? code : null,
|
|
24959
25111
|
name: crs.name || null,
|
|
24960
25112
|
description: crs.description || null,
|
|
24961
25113
|
wkt: crs.wkt || null,
|
|
24962
|
-
code_string: crs.code_string || ('EPSG:' + code)
|
|
25114
|
+
code_string: hasCode ? (crs.code_string || ('EPSG:' + code)) : null
|
|
24963
25115
|
};
|
|
24964
25116
|
}
|
|
24965
25117
|
|
|
25118
|
+
function addWktToCRS(meta, dataset, crsInfoArg) {
|
|
25119
|
+
if (!meta) return null;
|
|
25120
|
+
var info = dataset && dataset.info || {};
|
|
25121
|
+
if (meta.wkt && isWkt2(meta.wkt)) return meta;
|
|
25122
|
+
var crsInfo = crsInfoArg || getSafeDatasetCrsInfo(dataset);
|
|
25123
|
+
var crs = crsInfo && crsInfo.crs;
|
|
25124
|
+
var wkt = crs ? crsToWkt2(crs) : null;
|
|
25125
|
+
if (!wkt && meta.wkt) wkt = meta.wkt;
|
|
25126
|
+
if (!wkt && crs) wkt = crsToPrj(crs);
|
|
25127
|
+
if (!wkt && info.wkt1) wkt = info.wkt1;
|
|
25128
|
+
if (wkt) meta.wkt = wkt;
|
|
25129
|
+
return meta.code || meta.wkt ? meta : null;
|
|
25130
|
+
}
|
|
25131
|
+
|
|
25132
|
+
function getSafeDatasetCrsInfo(dataset) {
|
|
25133
|
+
try {
|
|
25134
|
+
return getDatasetCrsInfo(dataset);
|
|
25135
|
+
} catch (e) {
|
|
25136
|
+
return null;
|
|
25137
|
+
}
|
|
25138
|
+
}
|
|
25139
|
+
|
|
25140
|
+
function isWkt2(wkt) {
|
|
25141
|
+
return /^(GEODCRS|GEOGCRS|PROJCRS|VERTCRS|ENGCRS|BOUNDCRS|COMPOUNDCRS)\s*\[/i.test(String(wkt || '').trim());
|
|
25142
|
+
}
|
|
25143
|
+
|
|
24966
25144
|
function looksLikeEPSGCode(code) {
|
|
24967
25145
|
return code >= 2000 && code <= 1000000;
|
|
24968
25146
|
}
|
|
@@ -25092,7 +25270,7 @@ ${svg}
|
|
|
25092
25270
|
Object.keys(props).forEach(function(name) {
|
|
25093
25271
|
if (!isSupportedPropertyName(name)) return;
|
|
25094
25272
|
var value = props[name];
|
|
25095
|
-
var next = inferValueType(value);
|
|
25273
|
+
var next = inferValueType$1(value);
|
|
25096
25274
|
if (!next) return;
|
|
25097
25275
|
if (!(name in index)) {
|
|
25098
25276
|
index[name] = next;
|
|
@@ -25174,7 +25352,7 @@ ${svg}
|
|
|
25174
25352
|
fields.length == 1 && fields[0] == GeoJSON.ID_FIELD);
|
|
25175
25353
|
}
|
|
25176
25354
|
|
|
25177
|
-
function inferValueType(value) {
|
|
25355
|
+
function inferValueType$1(value) {
|
|
25178
25356
|
if (value === null || value === undefined) return null;
|
|
25179
25357
|
if (value instanceof Date) return 'DATETIME';
|
|
25180
25358
|
if (typeof value == 'boolean') return 'BOOLEAN';
|
|
@@ -25504,6 +25682,322 @@ ${svg}
|
|
|
25504
25682
|
return normalized;
|
|
25505
25683
|
}
|
|
25506
25684
|
|
|
25685
|
+
var writerPromise = null;
|
|
25686
|
+
var zstdPromise = null;
|
|
25687
|
+
var dynamicImportModule$1 = Function('id', 'return import(id)');
|
|
25688
|
+
|
|
25689
|
+
async function exportGeoParquet(dataset, opts, filenameOverride) {
|
|
25690
|
+
var writer = await loadGeoParquetWriter();
|
|
25691
|
+
var compression = await getGeoParquetCompression(opts);
|
|
25692
|
+
var extension = opts.extension || 'parquet';
|
|
25693
|
+
var files = [];
|
|
25694
|
+
if (opts.file) {
|
|
25695
|
+
extension = getFileExtension(opts.file) || extension;
|
|
25696
|
+
}
|
|
25697
|
+
dataset.layers.forEach(function(lyr) {
|
|
25698
|
+
var features = exportLayerAsGeoJSON(lyr, dataset, opts, true, null);
|
|
25699
|
+
var hasGeometry = features.some(function(feat) {
|
|
25700
|
+
return !!feat.geometry;
|
|
25701
|
+
});
|
|
25702
|
+
var output = buildGeoParquetColumns(features, hasGeometry);
|
|
25703
|
+
var writeOptions = {
|
|
25704
|
+
columnData: output.columnData,
|
|
25705
|
+
codec: compression.codec,
|
|
25706
|
+
compressors: compression.compressors,
|
|
25707
|
+
pageSize: compression.pageSize
|
|
25708
|
+
};
|
|
25709
|
+
if (hasGeometry) {
|
|
25710
|
+
writeOptions.kvMetadata = [{
|
|
25711
|
+
key: 'geo',
|
|
25712
|
+
value: JSON.stringify(buildGeoMetadata(features, dataset))
|
|
25713
|
+
}];
|
|
25714
|
+
} else {
|
|
25715
|
+
warn('GeoParquet export: layer has no geometry; writing attribute data only.');
|
|
25716
|
+
}
|
|
25717
|
+
var content = writer.parquetWriteBuffer(writeOptions);
|
|
25718
|
+
files.push({
|
|
25719
|
+
filename: filenameOverride || (lyr.name + '.' + extension),
|
|
25720
|
+
content: content
|
|
25721
|
+
});
|
|
25722
|
+
});
|
|
25723
|
+
return files;
|
|
25724
|
+
}
|
|
25725
|
+
|
|
25726
|
+
function buildGeoParquetColumns(features, includeGeometry) {
|
|
25727
|
+
var geometryName = 'geometry';
|
|
25728
|
+
var names = getPropertyNames(features);
|
|
25729
|
+
var columnData = [];
|
|
25730
|
+
if (features.length === 0) {
|
|
25731
|
+
stop$1('GeoParquet export requires at least one record');
|
|
25732
|
+
}
|
|
25733
|
+
if (includeGeometry) {
|
|
25734
|
+
columnData.push({
|
|
25735
|
+
name: geometryName,
|
|
25736
|
+
data: features.map(function(feat) {
|
|
25737
|
+
return feat.geometry || null;
|
|
25738
|
+
}),
|
|
25739
|
+
type: 'GEOMETRY'
|
|
25740
|
+
});
|
|
25741
|
+
}
|
|
25742
|
+
names.forEach(function(name) {
|
|
25743
|
+
var values = features.map(function(feat) {
|
|
25744
|
+
return feat.properties ? feat.properties[name] : null;
|
|
25745
|
+
});
|
|
25746
|
+
columnData.push(buildAttributeColumn(name, values));
|
|
25747
|
+
});
|
|
25748
|
+
if (columnData.length === 0) {
|
|
25749
|
+
stop$1('GeoParquet export requires geometry or attribute data');
|
|
25750
|
+
}
|
|
25751
|
+
return {columnData: columnData, geometryColumn: geometryName};
|
|
25752
|
+
}
|
|
25753
|
+
|
|
25754
|
+
function buildAttributeColumn(name, values) {
|
|
25755
|
+
var info = inferColumnType(values);
|
|
25756
|
+
return {
|
|
25757
|
+
name: name,
|
|
25758
|
+
data: values.map(function(value) {
|
|
25759
|
+
return normalizeFieldValue(value, info.type);
|
|
25760
|
+
}),
|
|
25761
|
+
type: info.type
|
|
25762
|
+
};
|
|
25763
|
+
}
|
|
25764
|
+
|
|
25765
|
+
function inferColumnType(values) {
|
|
25766
|
+
var type = null;
|
|
25767
|
+
for (var i = 0; i < values.length; i++) {
|
|
25768
|
+
var valueType = inferValueType(values[i]);
|
|
25769
|
+
if (!valueType) continue;
|
|
25770
|
+
if (!type) {
|
|
25771
|
+
type = valueType;
|
|
25772
|
+
} else if (type != valueType) {
|
|
25773
|
+
if ((type == 'INT32' || type == 'DOUBLE') &&
|
|
25774
|
+
(valueType == 'INT32' || valueType == 'DOUBLE')) {
|
|
25775
|
+
type = 'DOUBLE';
|
|
25776
|
+
} else {
|
|
25777
|
+
type = 'STRING';
|
|
25778
|
+
break;
|
|
25779
|
+
}
|
|
25780
|
+
}
|
|
25781
|
+
}
|
|
25782
|
+
return {type: type || 'STRING'};
|
|
25783
|
+
}
|
|
25784
|
+
|
|
25785
|
+
function inferValueType(value) {
|
|
25786
|
+
if (value === null || value === undefined) return null;
|
|
25787
|
+
if (typeof value == 'boolean') return 'BOOLEAN';
|
|
25788
|
+
if (typeof value == 'number') {
|
|
25789
|
+
if (!Number.isFinite(value)) return 'STRING';
|
|
25790
|
+
if (Math.floor(value) === value && value >= -2147483648 && value <= 2147483647) {
|
|
25791
|
+
return 'INT32';
|
|
25792
|
+
}
|
|
25793
|
+
return 'DOUBLE';
|
|
25794
|
+
}
|
|
25795
|
+
if (typeof value == 'bigint') return 'STRING';
|
|
25796
|
+
if (value instanceof Date) return 'TIMESTAMP';
|
|
25797
|
+
if (value instanceof Uint8Array) return 'BYTE_ARRAY';
|
|
25798
|
+
if (typeof Buffer == 'function' && Buffer.isBuffer(value)) return 'BYTE_ARRAY';
|
|
25799
|
+
if (Array.isArray(value) || utils.isObject(value)) return 'JSON';
|
|
25800
|
+
return 'STRING';
|
|
25801
|
+
}
|
|
25802
|
+
|
|
25803
|
+
function normalizeFieldValue(value, type) {
|
|
25804
|
+
if (value === undefined) return null;
|
|
25805
|
+
if (value === null) return null;
|
|
25806
|
+
if (type == 'TIMESTAMP') return value instanceof Date ? value : new Date(value);
|
|
25807
|
+
if (type == 'BYTE_ARRAY') {
|
|
25808
|
+
if (value instanceof Uint8Array) return value;
|
|
25809
|
+
if (typeof Buffer == 'function' && Buffer.isBuffer(value)) {
|
|
25810
|
+
return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
25811
|
+
}
|
|
25812
|
+
return null;
|
|
25813
|
+
}
|
|
25814
|
+
if (type == 'JSON') return value;
|
|
25815
|
+
if (type == 'BOOLEAN') return !!value;
|
|
25816
|
+
if (type == 'INT32' || type == 'DOUBLE') {
|
|
25817
|
+
var num = Number(value);
|
|
25818
|
+
return Number.isFinite(num) ? num : null;
|
|
25819
|
+
}
|
|
25820
|
+
return String(value);
|
|
25821
|
+
}
|
|
25822
|
+
|
|
25823
|
+
function getPropertyNames(features) {
|
|
25824
|
+
var index = {};
|
|
25825
|
+
features.forEach(function(feat) {
|
|
25826
|
+
var props = feat.properties || {};
|
|
25827
|
+
Object.keys(props).forEach(function(name) {
|
|
25828
|
+
index[name] = true;
|
|
25829
|
+
});
|
|
25830
|
+
});
|
|
25831
|
+
return Object.keys(index);
|
|
25832
|
+
}
|
|
25833
|
+
|
|
25834
|
+
function buildGeoMetadata(features, dataset) {
|
|
25835
|
+
var geomTypes = utils.uniq(features.map(function(feat) {
|
|
25836
|
+
return feat.geometry && feat.geometry.type || null;
|
|
25837
|
+
}).filter(Boolean));
|
|
25838
|
+
var crs = getGeoMetadataCrs(dataset);
|
|
25839
|
+
var geomMeta = {
|
|
25840
|
+
encoding: 'WKB',
|
|
25841
|
+
geometry_types: geomTypes
|
|
25842
|
+
};
|
|
25843
|
+
if (crs) {
|
|
25844
|
+
geomMeta.crs = crs;
|
|
25845
|
+
}
|
|
25846
|
+
return {
|
|
25847
|
+
version: '1.1.0',
|
|
25848
|
+
primary_column: 'geometry',
|
|
25849
|
+
columns: {
|
|
25850
|
+
geometry: geomMeta
|
|
25851
|
+
}
|
|
25852
|
+
};
|
|
25853
|
+
}
|
|
25854
|
+
|
|
25855
|
+
function getGeoMetadataCrs(dataset) {
|
|
25856
|
+
var info = dataset && dataset.info || {};
|
|
25857
|
+
if (info.geoparquet_crs && utils.isObject(info.geoparquet_crs)) {
|
|
25858
|
+
return info.geoparquet_crs;
|
|
25859
|
+
}
|
|
25860
|
+
return convertCrsToProjjson(info.crs_string, info.wkt1);
|
|
25861
|
+
}
|
|
25862
|
+
|
|
25863
|
+
function convertCrsToProjjson(crsString, wkt1) {
|
|
25864
|
+
var mproj = require$1('mproj');
|
|
25865
|
+
var converter = getProjjsonFromProj4Converter(mproj);
|
|
25866
|
+
if (!converter) return null;
|
|
25867
|
+
try {
|
|
25868
|
+
var crsObj = crsString ? parseCrsString$1(crsString) : (wkt1 ? parsePrj(wkt1) : null);
|
|
25869
|
+
if (!crsObj) return null;
|
|
25870
|
+
var projjson = converter(crsObj);
|
|
25871
|
+
if (utils.isString(projjson)) {
|
|
25872
|
+
projjson = JSON.parse(projjson);
|
|
25873
|
+
}
|
|
25874
|
+
return utils.isObject(projjson) ? projjson : null;
|
|
25875
|
+
} catch (e) {
|
|
25876
|
+
return null;
|
|
25877
|
+
}
|
|
25878
|
+
}
|
|
25879
|
+
|
|
25880
|
+
function getProjjsonFromProj4Converter(mproj) {
|
|
25881
|
+
if (mproj && typeof mproj.projjson_from_proj4 == 'function') {
|
|
25882
|
+
return mproj.projjson_from_proj4;
|
|
25883
|
+
}
|
|
25884
|
+
if (mproj && mproj.internal && typeof mproj.internal.projjson_from_proj4 == 'function') {
|
|
25885
|
+
return mproj.internal.projjson_from_proj4;
|
|
25886
|
+
}
|
|
25887
|
+
return null;
|
|
25888
|
+
}
|
|
25889
|
+
|
|
25890
|
+
async function loadGeoParquetWriter() {
|
|
25891
|
+
if (runningInBrowser()) {
|
|
25892
|
+
var mod = require$1('hyparquet-writer');
|
|
25893
|
+
if (mod && mod.default && !mod.parquetWriteBuffer) {
|
|
25894
|
+
mod = mod.default;
|
|
25895
|
+
}
|
|
25896
|
+
if (!mod || !mod.parquetWriteBuffer) {
|
|
25897
|
+
stop$1('GeoParquet writer library is not loaded');
|
|
25898
|
+
}
|
|
25899
|
+
return mod;
|
|
25900
|
+
}
|
|
25901
|
+
if (!writerPromise) {
|
|
25902
|
+
writerPromise = dynamicImportModule$1('hyparquet-writer');
|
|
25903
|
+
}
|
|
25904
|
+
var nodeMod = await writerPromise;
|
|
25905
|
+
return nodeMod.default && !nodeMod.parquetWriteBuffer ? nodeMod.default : nodeMod;
|
|
25906
|
+
}
|
|
25907
|
+
|
|
25908
|
+
async function getGeoParquetCompression(opts) {
|
|
25909
|
+
var codec = normalizeGeoParquetCompression(opts.compression);
|
|
25910
|
+
var level = validateGeoParquetCompressionLevel(opts.level, codec);
|
|
25911
|
+
if (codec != 'ZSTD') {
|
|
25912
|
+
return {codec: codec, compressors: null};
|
|
25913
|
+
}
|
|
25914
|
+
var zstd = await loadZstdLib();
|
|
25915
|
+
if (!zstd || typeof zstd.compress != 'function') {
|
|
25916
|
+
stop$1('GeoParquet ZSTD compressor is not loaded');
|
|
25917
|
+
}
|
|
25918
|
+
return {
|
|
25919
|
+
codec: codec,
|
|
25920
|
+
pageSize: getGeoParquetPageSize(level),
|
|
25921
|
+
compressors: {
|
|
25922
|
+
ZSTD: function(bytes) {
|
|
25923
|
+
return compressZstdPage(zstd, bytes, level);
|
|
25924
|
+
}
|
|
25925
|
+
}
|
|
25926
|
+
};
|
|
25927
|
+
}
|
|
25928
|
+
|
|
25929
|
+
function compressZstdPage(zstd, bytes, level) {
|
|
25930
|
+
var compressed;
|
|
25931
|
+
try {
|
|
25932
|
+
compressed = zstd.compress(bytes, level);
|
|
25933
|
+
} catch (e) {
|
|
25934
|
+
stop$1('Unable to apply GeoParquet ZSTD compression. Try a lower level= value.');
|
|
25935
|
+
}
|
|
25936
|
+
if (!compressed) {
|
|
25937
|
+
stop$1('Unable to apply GeoParquet ZSTD compression. Try a lower level= value.');
|
|
25938
|
+
}
|
|
25939
|
+
return compressed;
|
|
25940
|
+
}
|
|
25941
|
+
|
|
25942
|
+
function getGeoParquetPageSize(level) {
|
|
25943
|
+
return level >= 10 ? 64 * 1024 : undefined;
|
|
25944
|
+
}
|
|
25945
|
+
|
|
25946
|
+
function normalizeGeoParquetCompression(compression) {
|
|
25947
|
+
var str = compression === undefined || compression === null ? 'snappy' : String(compression).toLowerCase();
|
|
25948
|
+
if (str == 'snappy') return 'SNAPPY';
|
|
25949
|
+
if (str == 'zstd') return 'ZSTD';
|
|
25950
|
+
if (str == 'none' || str == 'uncompressed') return null;
|
|
25951
|
+
stop$1('Unsupported GeoParquet compression:', compression);
|
|
25952
|
+
}
|
|
25953
|
+
|
|
25954
|
+
function validateGeoParquetCompressionLevel(level, codec) {
|
|
25955
|
+
if (level === undefined) return undefined;
|
|
25956
|
+
if (codec != 'ZSTD') {
|
|
25957
|
+
stop$1('The level= option only applies with compression=zstd');
|
|
25958
|
+
}
|
|
25959
|
+
if (level >= 1 && level <= 22 && Math.floor(level) === level) {
|
|
25960
|
+
return level;
|
|
25961
|
+
}
|
|
25962
|
+
stop$1('GeoParquet ZSTD level= option must be an integer from 1 to 22');
|
|
25963
|
+
}
|
|
25964
|
+
|
|
25965
|
+
async function loadZstdLib() {
|
|
25966
|
+
var mod;
|
|
25967
|
+
if (runningInBrowser()) {
|
|
25968
|
+
mod = require$1('zstd-codec');
|
|
25969
|
+
} else {
|
|
25970
|
+
if (!zstdPromise) {
|
|
25971
|
+
zstdPromise = dynamicImportModule$1('zstd-codec');
|
|
25972
|
+
}
|
|
25973
|
+
mod = await zstdPromise;
|
|
25974
|
+
}
|
|
25975
|
+
if (mod && mod.default && !mod.ZstdCodec) {
|
|
25976
|
+
mod = mod.default;
|
|
25977
|
+
}
|
|
25978
|
+
if (!mod || !mod.ZstdCodec || typeof mod.ZstdCodec.run != 'function') {
|
|
25979
|
+
stop$1('GeoParquet ZSTD compressor is not loaded');
|
|
25980
|
+
}
|
|
25981
|
+
return initZstdCodec(mod.ZstdCodec);
|
|
25982
|
+
}
|
|
25983
|
+
|
|
25984
|
+
function initZstdCodec(codec) {
|
|
25985
|
+
return new Promise(function(resolve, reject) {
|
|
25986
|
+
try {
|
|
25987
|
+
codec.run(function(zstd) {
|
|
25988
|
+
var simple = new zstd.Simple();
|
|
25989
|
+
resolve({
|
|
25990
|
+
compress: function(bytes, level) {
|
|
25991
|
+
return simple.compress(bytes, level);
|
|
25992
|
+
}
|
|
25993
|
+
});
|
|
25994
|
+
});
|
|
25995
|
+
} catch (e) {
|
|
25996
|
+
reject(e);
|
|
25997
|
+
}
|
|
25998
|
+
});
|
|
25999
|
+
}
|
|
26000
|
+
|
|
25507
26001
|
function getOutputFormat(dataset, opts) {
|
|
25508
26002
|
var outFile = opts.file || null,
|
|
25509
26003
|
inFmt = dataset.info && dataset.info.input_formats && dataset.info.input_formats[0],
|
|
@@ -25547,6 +26041,8 @@ ${svg}
|
|
|
25547
26041
|
format = 'geopackage';
|
|
25548
26042
|
} else if (ext == 'fgb') {
|
|
25549
26043
|
format = 'flatgeobuf';
|
|
26044
|
+
} else if (ext == 'parquet' || ext == 'geoparquet') {
|
|
26045
|
+
format = 'geoparquet';
|
|
25550
26046
|
} else if (ext == 'svg') {
|
|
25551
26047
|
format = 'svg';
|
|
25552
26048
|
} else if (ext == 'kml' || ext == 'kmz') {
|
|
@@ -25607,6 +26103,9 @@ ${svg}
|
|
|
25607
26103
|
async function exportDatasets(datasets, opts) {
|
|
25608
26104
|
var format = getOutputFormat(datasets[0], opts);
|
|
25609
26105
|
var files;
|
|
26106
|
+
if (format != 'geoparquet' && (opts.compression || opts.level !== undefined)) {
|
|
26107
|
+
error('The compression= and level= options only apply to GeoParquet output');
|
|
26108
|
+
}
|
|
25610
26109
|
if (format == PACKAGE_EXT) {
|
|
25611
26110
|
opts = utils.defaults({compact: true}, opts);
|
|
25612
26111
|
return exportPackedDatasets(datasets, opts);
|
|
@@ -25637,6 +26136,16 @@ ${svg}
|
|
|
25637
26136
|
}
|
|
25638
26137
|
datasets.forEach(sortExportLayers);
|
|
25639
26138
|
files = await exportGeoPackage(datasets[0], opts);
|
|
26139
|
+
} else if (format == 'geoparquet') {
|
|
26140
|
+
var layerCount = datasets.reduce(function(sum, d) {
|
|
26141
|
+
return sum + d.layers.length;
|
|
26142
|
+
}, 0);
|
|
26143
|
+
var singleFileName = opts.file && layerCount == 1 ? opts.file : null;
|
|
26144
|
+
files = [];
|
|
26145
|
+
for (var i = 0; i < datasets.length; i++) {
|
|
26146
|
+
sortExportLayers(datasets[i]);
|
|
26147
|
+
files = files.concat(await exportGeoParquet(datasets[i], opts, singleFileName));
|
|
26148
|
+
}
|
|
25640
26149
|
} else {
|
|
25641
26150
|
files = datasets.reduce(function(memo, dataset) {
|
|
25642
26151
|
sortExportLayers(dataset);
|
|
@@ -26709,7 +27218,7 @@ ${svg}
|
|
|
26709
27218
|
});
|
|
26710
27219
|
|
|
26711
27220
|
function isSupportedOutputFormat(fmt) {
|
|
26712
|
-
var types = ['geojson', 'topojson', 'json', 'dsv', 'dbf', 'shapefile', 'svg', 'kml', PACKAGE_EXT, 'flatgeobuf', 'geopackage'];
|
|
27221
|
+
var types = ['geojson', 'topojson', 'json', 'dsv', 'dbf', 'shapefile', 'svg', 'kml', PACKAGE_EXT, 'flatgeobuf', 'geopackage', 'geoparquet'];
|
|
26713
27222
|
return types.indexOf(fmt) > -1;
|
|
26714
27223
|
}
|
|
26715
27224
|
|
|
@@ -26726,6 +27235,7 @@ ${svg}
|
|
|
26726
27235
|
shapefile: 'Shapefile',
|
|
26727
27236
|
flatgeobuf: 'Flatgeobuf',
|
|
26728
27237
|
geopackage: 'GeoPackage',
|
|
27238
|
+
geoparquet: 'GeoParquet',
|
|
26729
27239
|
svg: 'SVG'
|
|
26730
27240
|
}[fmt] || '';
|
|
26731
27241
|
}
|
|
@@ -26837,6 +27347,8 @@ ${svg}
|
|
|
26837
27347
|
} else if (o.format == 'tsv') {
|
|
26838
27348
|
o.format = 'dsv';
|
|
26839
27349
|
o.delimiter = o.delimiter || '\t';
|
|
27350
|
+
} else if (o.format == 'parquet') {
|
|
27351
|
+
o.format = 'geoparquet';
|
|
26840
27352
|
}
|
|
26841
27353
|
if (!isSupportedOutputFormat(o.format)) {
|
|
26842
27354
|
error('Unsupported output format:', o.format);
|
|
@@ -28095,7 +28607,7 @@ ${svg}
|
|
|
28095
28607
|
}
|
|
28096
28608
|
})
|
|
28097
28609
|
.option('format', {
|
|
28098
|
-
describe: 'options: shapefile,geojson,topojson,flatgeobuf,geopackage,json,dbf,csv,tsv,svg'
|
|
28610
|
+
describe: 'options: shapefile,geojson,topojson,flatgeobuf,geopackage,geoparquet,json,dbf,csv,tsv,svg'
|
|
28099
28611
|
})
|
|
28100
28612
|
.option('target', targetOpt)
|
|
28101
28613
|
.option('force', {
|
|
@@ -28272,6 +28784,13 @@ ${svg}
|
|
|
28272
28784
|
type: 'flag',
|
|
28273
28785
|
describe: '[CSV] export numbers with decimal commas not points'
|
|
28274
28786
|
})
|
|
28787
|
+
.option('compression', {
|
|
28788
|
+
describe: '[GeoParquet] options: snappy,zstd,none (default is snappy)'
|
|
28789
|
+
})
|
|
28790
|
+
.option('level', {
|
|
28791
|
+
describe: '[GeoParquet] zstd compression level',
|
|
28792
|
+
type: 'integer'
|
|
28793
|
+
})
|
|
28275
28794
|
.option('show-all', {
|
|
28276
28795
|
type: 'flag',
|
|
28277
28796
|
describe: '[Snapshot] show all layers in Web UI'
|
|
@@ -32739,19 +33258,43 @@ ${svg}
|
|
|
32739
33258
|
dataset.info = dataset.info || {};
|
|
32740
33259
|
var crs = normalizeCRSMeta(headerMeta.crs || null);
|
|
32741
33260
|
dataset.info.flatgeobuf_crs = crs;
|
|
32742
|
-
if (crs
|
|
32743
|
-
dataset
|
|
32744
|
-
await initProjLibrary({crs: dataset.info.crs_string});
|
|
32745
|
-
} else if (crs && crs.wkt) {
|
|
32746
|
-
warnOnce('Unable to import WKT2 CRS from FlatGeobuf');
|
|
33261
|
+
if (crs) {
|
|
33262
|
+
await importFlatGeobufCRS(dataset, crs);
|
|
32747
33263
|
}
|
|
32748
33264
|
return dataset;
|
|
32749
33265
|
}
|
|
32750
33266
|
|
|
33267
|
+
async function importFlatGeobufCRS(dataset, crs) {
|
|
33268
|
+
var crsString = crs.org && crs.code ? crs.org.toLowerCase() + ':' + crs.code : null;
|
|
33269
|
+
if (crsString) {
|
|
33270
|
+
try {
|
|
33271
|
+
await initProjLibrary({crs: crsString});
|
|
33272
|
+
dataset.info.crs_string = crsString;
|
|
33273
|
+
return;
|
|
33274
|
+
} catch (e) {
|
|
33275
|
+
// Fall through and try WKT metadata if an authority lookup is unavailable.
|
|
33276
|
+
}
|
|
33277
|
+
}
|
|
33278
|
+
if (crs.wkt) {
|
|
33279
|
+
try {
|
|
33280
|
+
// Validate that mproj can parse the WKT, then keep the equivalent Proj4
|
|
33281
|
+
// string in crs_string so downstream projection handling works normally.
|
|
33282
|
+
parseWkt(crs.wkt);
|
|
33283
|
+
dataset.info.crs_string = wktToProj(crs.wkt);
|
|
33284
|
+
return;
|
|
33285
|
+
} catch (e) {
|
|
33286
|
+
warnOnce('Unable to import WKT CRS from FlatGeobuf');
|
|
33287
|
+
}
|
|
33288
|
+
}
|
|
33289
|
+
}
|
|
33290
|
+
|
|
32751
33291
|
function normalizeCRSMeta(crs) {
|
|
32752
33292
|
if (!crs) return null;
|
|
32753
33293
|
var code = +crs.code;
|
|
32754
|
-
if (
|
|
33294
|
+
if (!Number.isFinite(code) || code <= 0) {
|
|
33295
|
+
return Object.assign({}, crs, {code: null});
|
|
33296
|
+
}
|
|
33297
|
+
if (crs.org) return crs;
|
|
32755
33298
|
code = Math.round(code);
|
|
32756
33299
|
if (code >= 2000 && code <= 1000000) {
|
|
32757
33300
|
// Some encoders write code but omit authority org; default to EPSG.
|
|
@@ -33253,6 +33796,395 @@ ${svg}
|
|
|
33253
33796
|
return obj;
|
|
33254
33797
|
}
|
|
33255
33798
|
|
|
33799
|
+
var hyparquetPromise = null;
|
|
33800
|
+
var compressorsPromise = null;
|
|
33801
|
+
var dynamicImportModule = Function('id', 'return import(id)');
|
|
33802
|
+
var mproj = null;
|
|
33803
|
+
|
|
33804
|
+
async function importGeoParquet(input, optsArg) {
|
|
33805
|
+
var opts = optsArg || {};
|
|
33806
|
+
var hyparquet = await loadHyparquetLib();
|
|
33807
|
+
var source = getGeoParquetSource(input);
|
|
33808
|
+
var file = await getHyparquetFile(source, hyparquet);
|
|
33809
|
+
var metadata = await hyparquet.parquetMetadataAsync(file);
|
|
33810
|
+
var geo = parseGeoParquetMetadata(metadata);
|
|
33811
|
+
var compressors = await loadHyparquetCompressors();
|
|
33812
|
+
var rows = await hyparquet.parquetReadObjects({
|
|
33813
|
+
file: file,
|
|
33814
|
+
compressors: compressors,
|
|
33815
|
+
rowFormat: 'object'
|
|
33816
|
+
});
|
|
33817
|
+
var geometryColumn = getGeoParquetGeometryColumn(rows, geo);
|
|
33818
|
+
if (!geometryColumn && hasUnsupportedGeometryEncoding(geo)) {
|
|
33819
|
+
warnOnce('Unable to import GeoParquet geometry: native encodings are not supported (expected WKB). Importing attribute data only.');
|
|
33820
|
+
}
|
|
33821
|
+
var dataset = convertGeoParquetRows(rows, geo, opts, geometryColumn);
|
|
33822
|
+
var crs = getGeoParquetCrs(geo, geometryColumn);
|
|
33823
|
+
dataset.info = dataset.info || {};
|
|
33824
|
+
dataset.info.geoparquet_geo = geo;
|
|
33825
|
+
dataset.info.geoparquet_crs = crs;
|
|
33826
|
+
if (crs) {
|
|
33827
|
+
var crsString = await resolveGeoParquetCrsString(crs);
|
|
33828
|
+
if (!crsString) {
|
|
33829
|
+
warnOnce('Unable to import CRS from GeoParquet metadata');
|
|
33830
|
+
}
|
|
33831
|
+
dataset.info.crs_string = crsString || null;
|
|
33832
|
+
}
|
|
33833
|
+
return dataset;
|
|
33834
|
+
}
|
|
33835
|
+
|
|
33836
|
+
async function loadHyparquetLib() {
|
|
33837
|
+
if (runningInBrowser()) {
|
|
33838
|
+
var mod = require$1('hyparquet');
|
|
33839
|
+
if (mod && mod.default && !mod.parquetReadObjects) {
|
|
33840
|
+
mod = mod.default;
|
|
33841
|
+
}
|
|
33842
|
+
if (!mod || !mod.parquetReadObjects || !mod.parquetMetadataAsync) {
|
|
33843
|
+
stop$1('GeoParquet library is not loaded');
|
|
33844
|
+
}
|
|
33845
|
+
return mod;
|
|
33846
|
+
}
|
|
33847
|
+
if (!hyparquetPromise) {
|
|
33848
|
+
hyparquetPromise = dynamicImportModule('hyparquet');
|
|
33849
|
+
}
|
|
33850
|
+
var nodeMod = await hyparquetPromise;
|
|
33851
|
+
return nodeMod.default && !nodeMod.parquetReadObjects ? nodeMod.default : nodeMod;
|
|
33852
|
+
}
|
|
33853
|
+
|
|
33854
|
+
async function loadHyparquetCompressors() {
|
|
33855
|
+
if (runningInBrowser()) {
|
|
33856
|
+
return getHyparquetCompressors(require$1('hyparquet-compressors'));
|
|
33857
|
+
}
|
|
33858
|
+
if (!compressorsPromise) {
|
|
33859
|
+
compressorsPromise = dynamicImportModule('hyparquet-compressors');
|
|
33860
|
+
}
|
|
33861
|
+
return getHyparquetCompressors(await compressorsPromise);
|
|
33862
|
+
}
|
|
33863
|
+
|
|
33864
|
+
function getHyparquetCompressors(mod) {
|
|
33865
|
+
if (mod && mod.default && !mod.compressors) {
|
|
33866
|
+
mod = mod.default;
|
|
33867
|
+
}
|
|
33868
|
+
if (!mod || !mod.compressors) {
|
|
33869
|
+
stop$1('GeoParquet compression library is not loaded');
|
|
33870
|
+
}
|
|
33871
|
+
return mod.compressors;
|
|
33872
|
+
}
|
|
33873
|
+
|
|
33874
|
+
function getGeoParquetSource(input) {
|
|
33875
|
+
if (!input) return null;
|
|
33876
|
+
if (Object.prototype.hasOwnProperty.call(input, 'content')) {
|
|
33877
|
+
return input.content || input.filename || null;
|
|
33878
|
+
}
|
|
33879
|
+
return input;
|
|
33880
|
+
}
|
|
33881
|
+
|
|
33882
|
+
async function getHyparquetFile(source, hyparquet) {
|
|
33883
|
+
if (!source) {
|
|
33884
|
+
stop$1('Missing GeoParquet data');
|
|
33885
|
+
}
|
|
33886
|
+
if (utils.isString(source)) {
|
|
33887
|
+
if (!hyparquet.asyncBufferFromFile) {
|
|
33888
|
+
stop$1('Unable to read GeoParquet file path');
|
|
33889
|
+
}
|
|
33890
|
+
return hyparquet.asyncBufferFromFile(source);
|
|
33891
|
+
}
|
|
33892
|
+
return toArrayBuffer(source);
|
|
33893
|
+
}
|
|
33894
|
+
|
|
33895
|
+
function toArrayBuffer(content) {
|
|
33896
|
+
if (content instanceof ArrayBuffer) {
|
|
33897
|
+
return content;
|
|
33898
|
+
}
|
|
33899
|
+
if (content instanceof Uint8Array) {
|
|
33900
|
+
return content.buffer.slice(content.byteOffset, content.byteOffset + content.byteLength);
|
|
33901
|
+
}
|
|
33902
|
+
if (typeof Buffer == 'function' && Buffer.isBuffer(content)) {
|
|
33903
|
+
return content.buffer.slice(content.byteOffset, content.byteOffset + content.byteLength);
|
|
33904
|
+
}
|
|
33905
|
+
if (ArrayBuffer.isView(content)) {
|
|
33906
|
+
return content.buffer.slice(content.byteOffset, content.byteOffset + content.byteLength);
|
|
33907
|
+
}
|
|
33908
|
+
if (utils.isArray(content)) {
|
|
33909
|
+
return new Uint8Array(content).buffer;
|
|
33910
|
+
}
|
|
33911
|
+
stop$1('Unsupported GeoParquet input type');
|
|
33912
|
+
}
|
|
33913
|
+
|
|
33914
|
+
function convertGeoParquetRows(rows, geo, opts, geometryColumnArg) {
|
|
33915
|
+
var importer = new GeoJSONParser(opts);
|
|
33916
|
+
var geometryColumn = geometryColumnArg === undefined ?
|
|
33917
|
+
getGeoParquetGeometryColumn(rows, geo) :
|
|
33918
|
+
geometryColumnArg;
|
|
33919
|
+
var geometryColumns = getGeoParquetGeometryColumns(geo);
|
|
33920
|
+
rows.forEach(function(row) {
|
|
33921
|
+
if (!utils.isObject(row)) return;
|
|
33922
|
+
var feature = convertGeoParquetRow(row, geometryColumn, geometryColumns);
|
|
33923
|
+
importer.parseObject(feature);
|
|
33924
|
+
});
|
|
33925
|
+
return importer.done();
|
|
33926
|
+
}
|
|
33927
|
+
|
|
33928
|
+
function convertGeoParquetRow(row, geometryColumn, geometryColumns) {
|
|
33929
|
+
var feature = {
|
|
33930
|
+
type: 'Feature',
|
|
33931
|
+
properties: {},
|
|
33932
|
+
geometry: null
|
|
33933
|
+
};
|
|
33934
|
+
if (geometryColumn && row[geometryColumn] !== undefined) {
|
|
33935
|
+
feature.geometry = row[geometryColumn] || null;
|
|
33936
|
+
}
|
|
33937
|
+
for (var key in row) {
|
|
33938
|
+
if (!Object.prototype.hasOwnProperty.call(row, key)) continue;
|
|
33939
|
+
if (key == geometryColumn || geometryColumns.indexOf(key) > -1) continue;
|
|
33940
|
+
feature.properties[key] = normalizeGeoParquetValue(row[key], key);
|
|
33941
|
+
}
|
|
33942
|
+
return feature;
|
|
33943
|
+
}
|
|
33944
|
+
|
|
33945
|
+
function normalizeGeoParquetValue(val, fieldName) {
|
|
33946
|
+
if (typeof val == 'bigint') {
|
|
33947
|
+
return normalizeBigIntValue(val, fieldName);
|
|
33948
|
+
}
|
|
33949
|
+
if (Array.isArray(val)) {
|
|
33950
|
+
return val.map(function(item) {
|
|
33951
|
+
return normalizeGeoParquetValue(item, fieldName);
|
|
33952
|
+
});
|
|
33953
|
+
}
|
|
33954
|
+
if (val && utils.isObject(val)) {
|
|
33955
|
+
var out = {};
|
|
33956
|
+
for (var key in val) {
|
|
33957
|
+
if (Object.prototype.hasOwnProperty.call(val, key)) {
|
|
33958
|
+
out[key] = normalizeGeoParquetValue(val[key], fieldName);
|
|
33959
|
+
}
|
|
33960
|
+
}
|
|
33961
|
+
return out;
|
|
33962
|
+
}
|
|
33963
|
+
return val;
|
|
33964
|
+
}
|
|
33965
|
+
|
|
33966
|
+
function normalizeBigIntValue(val, fieldName) {
|
|
33967
|
+
var num = Number(val);
|
|
33968
|
+
if (!Number.isFinite(num)) {
|
|
33969
|
+
warnOnce('GeoParquet field "' + fieldName + '" contains BigInt values outside JavaScript Number range; precision will be lost.');
|
|
33970
|
+
return num;
|
|
33971
|
+
}
|
|
33972
|
+
if (BigInt(Math.trunc(num)) !== val) {
|
|
33973
|
+
warnOnce('GeoParquet field "' + fieldName + '" contains BigInt values that exceed Number.MAX_SAFE_INTEGER; precision will be lost.');
|
|
33974
|
+
}
|
|
33975
|
+
return num;
|
|
33976
|
+
}
|
|
33977
|
+
|
|
33978
|
+
function getGeoParquetGeometryColumns(geo) {
|
|
33979
|
+
if (!geo || !utils.isObject(geo.columns)) return [];
|
|
33980
|
+
return Object.keys(geo.columns);
|
|
33981
|
+
}
|
|
33982
|
+
|
|
33983
|
+
function getGeoParquetGeometryColumn(rows, geo) {
|
|
33984
|
+
var row = rows && rows.length > 0 && utils.isObject(rows[0]) ? rows[0] : null;
|
|
33985
|
+
var keys = row ? Object.keys(row) : [];
|
|
33986
|
+
var candidate;
|
|
33987
|
+
if (geo && utils.isObject(geo.columns)) {
|
|
33988
|
+
var wkbColumns = getWkbGeometryColumns(geo);
|
|
33989
|
+
candidate = geo.primary_column;
|
|
33990
|
+
if (candidate && wkbColumns.indexOf(candidate) > -1 && keys.indexOf(candidate) > -1) {
|
|
33991
|
+
return candidate;
|
|
33992
|
+
}
|
|
33993
|
+
candidate = wkbColumns.find(function(name) {
|
|
33994
|
+
return keys.indexOf(name) > -1;
|
|
33995
|
+
});
|
|
33996
|
+
if (candidate) return candidate;
|
|
33997
|
+
return null;
|
|
33998
|
+
}
|
|
33999
|
+
if (keys.indexOf('geometry') > -1) {
|
|
34000
|
+
return 'geometry';
|
|
34001
|
+
}
|
|
34002
|
+
candidate = keys.find(function(key) {
|
|
34003
|
+
return looksLikeGeoJSONGeometry(row[key]);
|
|
34004
|
+
});
|
|
34005
|
+
return candidate || null;
|
|
34006
|
+
}
|
|
34007
|
+
|
|
34008
|
+
function getWkbGeometryColumns(geo) {
|
|
34009
|
+
if (!geo || !utils.isObject(geo.columns)) return [];
|
|
34010
|
+
return Object.keys(geo.columns).filter(function(name) {
|
|
34011
|
+
var encoding = geo.columns[name] && geo.columns[name].encoding;
|
|
34012
|
+
return utils.isString(encoding) && encoding.toUpperCase() == 'WKB';
|
|
34013
|
+
});
|
|
34014
|
+
}
|
|
34015
|
+
|
|
34016
|
+
function hasUnsupportedGeometryEncoding(geo) {
|
|
34017
|
+
if (!geo || !utils.isObject(geo.columns)) return false;
|
|
34018
|
+
var columnNames = Object.keys(geo.columns);
|
|
34019
|
+
if (columnNames.length === 0) return false;
|
|
34020
|
+
return getWkbGeometryColumns(geo).length === 0;
|
|
34021
|
+
}
|
|
34022
|
+
|
|
34023
|
+
function looksLikeGeoJSONGeometry(obj) {
|
|
34024
|
+
return !!(obj && utils.isObject(obj) && utils.isString(obj.type));
|
|
34025
|
+
}
|
|
34026
|
+
|
|
34027
|
+
function parseGeoParquetMetadata(metadata) {
|
|
34028
|
+
var kv = getParquetKeyValueMetadata(metadata);
|
|
34029
|
+
var entry = kv.find(function(item) {
|
|
34030
|
+
return getMetadataKey(item) == 'geo';
|
|
34031
|
+
});
|
|
34032
|
+
var value = entry ? getMetadataValue(entry) : null;
|
|
34033
|
+
if (!value) return null;
|
|
34034
|
+
if (utils.isObject(value)) return value;
|
|
34035
|
+
try {
|
|
34036
|
+
return JSON.parse(normalizeMetadataString(value));
|
|
34037
|
+
} catch (e) {
|
|
34038
|
+
warnOnce('Unable to parse GeoParquet metadata');
|
|
34039
|
+
return null;
|
|
34040
|
+
}
|
|
34041
|
+
}
|
|
34042
|
+
|
|
34043
|
+
function getParquetKeyValueMetadata(metadata) {
|
|
34044
|
+
if (!metadata) return [];
|
|
34045
|
+
if (Array.isArray(metadata.key_value_metadata)) {
|
|
34046
|
+
return metadata.key_value_metadata;
|
|
34047
|
+
}
|
|
34048
|
+
if (Array.isArray(metadata.keyValueMetadata)) {
|
|
34049
|
+
return metadata.keyValueMetadata;
|
|
34050
|
+
}
|
|
34051
|
+
if (utils.isObject(metadata.metadata)) {
|
|
34052
|
+
return Object.keys(metadata.metadata).map(function(key) {
|
|
34053
|
+
return {key: key, value: metadata.metadata[key]};
|
|
34054
|
+
});
|
|
34055
|
+
}
|
|
34056
|
+
return [];
|
|
34057
|
+
}
|
|
34058
|
+
|
|
34059
|
+
function getMetadataKey(entry) {
|
|
34060
|
+
if (!entry || !utils.isObject(entry)) return null;
|
|
34061
|
+
return entry.key || entry.name || null;
|
|
34062
|
+
}
|
|
34063
|
+
|
|
34064
|
+
function getMetadataValue(entry) {
|
|
34065
|
+
if (!entry || !utils.isObject(entry)) return null;
|
|
34066
|
+
return entry.value ?? entry.val ?? null;
|
|
34067
|
+
}
|
|
34068
|
+
|
|
34069
|
+
function normalizeMetadataString(value) {
|
|
34070
|
+
if (utils.isString(value)) return value;
|
|
34071
|
+
if (value instanceof Uint8Array) {
|
|
34072
|
+
return new TextDecoder('utf-8').decode(value);
|
|
34073
|
+
}
|
|
34074
|
+
if (typeof Buffer == 'function' && Buffer.isBuffer(value)) {
|
|
34075
|
+
return value.toString('utf-8');
|
|
34076
|
+
}
|
|
34077
|
+
return String(value);
|
|
34078
|
+
}
|
|
34079
|
+
|
|
34080
|
+
function getGeoParquetCrs(geo, geometryColumn) {
|
|
34081
|
+
if (!geo || !utils.isObject(geo.columns)) return null;
|
|
34082
|
+
if (geometryColumn && geo.columns[geometryColumn]) {
|
|
34083
|
+
return geo.columns[geometryColumn].crs ?? null;
|
|
34084
|
+
}
|
|
34085
|
+
var cols = Object.keys(geo.columns);
|
|
34086
|
+
for (var i = 0; i < cols.length; i++) {
|
|
34087
|
+
var crs = geo.columns[cols[i]].crs;
|
|
34088
|
+
if (crs) return crs;
|
|
34089
|
+
}
|
|
34090
|
+
return null;
|
|
34091
|
+
}
|
|
34092
|
+
|
|
34093
|
+
function getGeoParquetAuthority(crs) {
|
|
34094
|
+
var match = findPrimaryAuthorityId(crs);
|
|
34095
|
+
if (!match) return null;
|
|
34096
|
+
var org = String(match.authority || '').toUpperCase();
|
|
34097
|
+
var code = Number(match.code);
|
|
34098
|
+
if (!org || !Number.isFinite(code)) return null;
|
|
34099
|
+
if (org != 'EPSG' && org != 'ESRI') return null;
|
|
34100
|
+
return {
|
|
34101
|
+
org: org,
|
|
34102
|
+
code: Math.round(code)
|
|
34103
|
+
};
|
|
34104
|
+
}
|
|
34105
|
+
|
|
34106
|
+
async function resolveGeoParquetCrsString(crs) {
|
|
34107
|
+
var candidates = getGeoParquetCrsStrings(crs);
|
|
34108
|
+
for (var i = 0; i < candidates.length; i++) {
|
|
34109
|
+
try {
|
|
34110
|
+
parseCrsString$1(candidates[i]);
|
|
34111
|
+
await initProjLibrary({crs: candidates[i]});
|
|
34112
|
+
return candidates[i];
|
|
34113
|
+
} catch (e) {
|
|
34114
|
+
// Keep trying candidates; if none initialize, caller will warn.
|
|
34115
|
+
}
|
|
34116
|
+
}
|
|
34117
|
+
return null;
|
|
34118
|
+
}
|
|
34119
|
+
|
|
34120
|
+
function getGeoParquetCrsStrings(crs) {
|
|
34121
|
+
var strings = [];
|
|
34122
|
+
var authority = getGeoParquetAuthority(crs);
|
|
34123
|
+
if (authority) {
|
|
34124
|
+
strings.push(authority.org.toLowerCase() + ':' + authority.code);
|
|
34125
|
+
}
|
|
34126
|
+
var proj4 = convertProjjsonToProj4(crs);
|
|
34127
|
+
if (proj4 && strings.indexOf(proj4) == -1) {
|
|
34128
|
+
strings.push(proj4);
|
|
34129
|
+
}
|
|
34130
|
+
return strings;
|
|
34131
|
+
}
|
|
34132
|
+
|
|
34133
|
+
function convertProjjsonToProj4(crs) {
|
|
34134
|
+
var converter = getProjjsonToProj4Converter();
|
|
34135
|
+
if (!converter) return null;
|
|
34136
|
+
try {
|
|
34137
|
+
return converter(crs);
|
|
34138
|
+
} catch (e) {
|
|
34139
|
+
return null;
|
|
34140
|
+
}
|
|
34141
|
+
}
|
|
34142
|
+
|
|
34143
|
+
function getProjjsonToProj4Converter() {
|
|
34144
|
+
if (!mproj) {
|
|
34145
|
+
mproj = require$1('mproj');
|
|
34146
|
+
}
|
|
34147
|
+
if (mproj && typeof mproj.projjson_to_proj4 == 'function') {
|
|
34148
|
+
return mproj.projjson_to_proj4;
|
|
34149
|
+
}
|
|
34150
|
+
if (mproj && mproj.internal && typeof mproj.internal.projjson_to_proj4 == 'function') {
|
|
34151
|
+
return mproj.internal.projjson_to_proj4;
|
|
34152
|
+
}
|
|
34153
|
+
return null;
|
|
34154
|
+
}
|
|
34155
|
+
|
|
34156
|
+
function findPrimaryAuthorityId(crs) {
|
|
34157
|
+
if (!crs || !utils.isObject(crs)) return null;
|
|
34158
|
+
if (utils.isString(crs)) {
|
|
34159
|
+
return parseAuthorityString(crs);
|
|
34160
|
+
}
|
|
34161
|
+
var match = parseAuthorityObject(crs.id);
|
|
34162
|
+
if (match) return match;
|
|
34163
|
+
if (crs.base_crs && utils.isObject(crs.base_crs)) {
|
|
34164
|
+
match = parseAuthorityObject(crs.base_crs.id);
|
|
34165
|
+
if (match) return match;
|
|
34166
|
+
}
|
|
34167
|
+
return null;
|
|
34168
|
+
}
|
|
34169
|
+
|
|
34170
|
+
function parseAuthorityObject(id) {
|
|
34171
|
+
if (!id || !utils.isObject(id)) return null;
|
|
34172
|
+
if (id.authority === undefined || id.code === undefined) return null;
|
|
34173
|
+
return {
|
|
34174
|
+
authority: id.authority,
|
|
34175
|
+
code: id.code
|
|
34176
|
+
};
|
|
34177
|
+
}
|
|
34178
|
+
|
|
34179
|
+
function parseAuthorityString(str) {
|
|
34180
|
+
var match = /^([A-Za-z]+)\s*:\s*([0-9]+)$/.exec(str);
|
|
34181
|
+
if (!match) return null;
|
|
34182
|
+
return {
|
|
34183
|
+
authority: match[1],
|
|
34184
|
+
code: Number(match[2])
|
|
34185
|
+
};
|
|
34186
|
+
}
|
|
34187
|
+
|
|
33256
34188
|
var INHERITED_STYLE_KEYS = [
|
|
33257
34189
|
'fill', 'fill-opacity',
|
|
33258
34190
|
'stroke', 'stroke-width', 'stroke-opacity', 'stroke-dasharray',
|
|
@@ -34204,6 +35136,8 @@ ${svg}
|
|
|
34204
35136
|
stop$1("FlatGeobuf import requires async import path");
|
|
34205
35137
|
} else if (obj.gpkg) {
|
|
34206
35138
|
stop$1("GeoPackage import requires async import path");
|
|
35139
|
+
} else if (obj.parquet) {
|
|
35140
|
+
stop$1("GeoParquet import requires async import path");
|
|
34207
35141
|
}
|
|
34208
35142
|
|
|
34209
35143
|
return finalizeImportedDataset(dataset, dataFmt, data, opts);
|
|
@@ -34220,6 +35154,10 @@ ${svg}
|
|
|
34220
35154
|
dataFmt = 'geopackage';
|
|
34221
35155
|
data = obj.gpkg;
|
|
34222
35156
|
dataset = await importGeoPackage(data, opts);
|
|
35157
|
+
} else if (obj.parquet) {
|
|
35158
|
+
dataFmt = 'geoparquet';
|
|
35159
|
+
data = obj.parquet;
|
|
35160
|
+
dataset = await importGeoParquet(data, opts);
|
|
34223
35161
|
} else {
|
|
34224
35162
|
return importContent(obj, opts);
|
|
34225
35163
|
}
|
|
@@ -34711,7 +35649,7 @@ ${svg}
|
|
|
34711
35649
|
if (fileType == 'shp' && !input.dbf) {
|
|
34712
35650
|
message(utils.format("[%s] .dbf file is missing - shapes imported without attribute data.", path));
|
|
34713
35651
|
}
|
|
34714
|
-
return fileType == 'gpkg' || fileType == 'fgb' ? importContentAsync(input, opts) : importContent(input, opts);
|
|
35652
|
+
return fileType == 'gpkg' || fileType == 'fgb' || fileType == 'parquet' ? importContentAsync(input, opts) : importContent(input, opts);
|
|
34715
35653
|
}
|
|
34716
35654
|
|
|
34717
35655
|
// Import multiple files to a single dataset
|
|
@@ -53474,7 +54412,7 @@ ${svg}
|
|
|
53474
54412
|
});
|
|
53475
54413
|
}
|
|
53476
54414
|
|
|
53477
|
-
var version = "0.7.
|
|
54415
|
+
var version = "0.7.9";
|
|
53478
54416
|
|
|
53479
54417
|
// Parse command line args into commands and run them
|
|
53480
54418
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|