@loaders.gl/flatgeobuf 3.1.0-beta.5 → 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { LoaderWithParser } from '@loaders.gl/loader-utils';
2
2
  import { FlatGeobufLoader as FlatGeobufWorkerLoader } from './flatgeobuf-loader';
3
- import parseFlatGeobuf, { parseFlatGeobufInBatches } from './lib/parse-flatgeobuf';
3
+ import { parseFlatGeobuf, parseFlatGeobufInBatches } from './lib/parse-flatgeobuf';
4
4
  export { FlatGeobufWorkerLoader };
5
5
  export declare const FlatGeobufLoader: {
6
6
  parse: (arrayBuffer: any, options: any) => Promise<any>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAC,gBAAgB,IAAI,sBAAsB,EAAC,MAAM,qBAAqB,CAAC;AAC/E,OAAO,eAAe,EAAE,EAAC,wBAAwB,EAAC,MAAM,wBAAwB,CAAC;AAEjF,OAAO,EAAC,sBAAsB,EAAC,CAAC;AAEhC,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;CAM5B,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,gBAAmC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAC,gBAAgB,IAAI,sBAAsB,EAAC,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EAAC,eAAe,EAAE,wBAAwB,EAAC,MAAM,wBAAwB,CAAC;AAEjF,OAAO,EAAC,sBAAsB,EAAC,CAAC;AAEhC,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;CAM5B,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,gBAAmC,CAAC"}
package/dist/index.js CHANGED
@@ -1,32 +1,13 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
- }) : (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- o[k2] = m[k];
8
- }));
9
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
- Object.defineProperty(o, "default", { enumerable: true, value: v });
11
- }) : function(o, v) {
12
- o["default"] = v;
13
- });
14
- var __importStar = (this && this.__importStar) || function (mod) {
15
- if (mod && mod.__esModule) return mod;
16
- var result = {};
17
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
- __setModuleDefault(result, mod);
19
- return result;
20
- };
21
2
  Object.defineProperty(exports, "__esModule", { value: true });
22
3
  exports._typecheckFlatGeobufLoader = exports.FlatGeobufLoader = exports.FlatGeobufWorkerLoader = void 0;
23
4
  const flatgeobuf_loader_1 = require("./flatgeobuf-loader");
24
5
  Object.defineProperty(exports, "FlatGeobufWorkerLoader", { enumerable: true, get: function () { return flatgeobuf_loader_1.FlatGeobufLoader; } });
25
- const parse_flatgeobuf_1 = __importStar(require("./lib/parse-flatgeobuf"));
6
+ const parse_flatgeobuf_1 = require("./lib/parse-flatgeobuf");
26
7
  exports.FlatGeobufLoader = {
27
8
  ...flatgeobuf_loader_1.FlatGeobufLoader,
28
- parse: async (arrayBuffer, options) => (0, parse_flatgeobuf_1.default)(arrayBuffer, options),
29
- parseSync: parse_flatgeobuf_1.default,
9
+ parse: async (arrayBuffer, options) => (0, parse_flatgeobuf_1.parseFlatGeobuf)(arrayBuffer, options),
10
+ parseSync: parse_flatgeobuf_1.parseFlatGeobuf,
30
11
  parseInBatchesFromStream: parse_flatgeobuf_1.parseFlatGeobufInBatches,
31
12
  binary: true
32
13
  };
@@ -0,0 +1,20 @@
1
+ export declare function fromGeometry(geometry: any, type: any): {
2
+ positions: {
3
+ value: any;
4
+ size: number;
5
+ };
6
+ } | {
7
+ positions: {
8
+ value: Float64Array;
9
+ size: any;
10
+ };
11
+ primitivePolygonIndices: {
12
+ value: Uint32Array;
13
+ size: number;
14
+ };
15
+ polygonIndices: {
16
+ value: Uint32Array;
17
+ size: number;
18
+ };
19
+ };
20
+ //# sourceMappingURL=binary-geometries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binary-geometries.d.ts","sourceRoot":"","sources":["../../src/lib/binary-geometries.ts"],"names":[],"mappings":"AAgIA,wBAAgB,YAAY,CAAC,QAAQ,KAAA,EAAE,IAAI,KAAA;;;;;;;;;;;;;;;;;;EAe1C"}
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fromGeometry = void 0;
4
+ const header_generated_1 = require("flatgeobuf/lib/cjs/header_generated");
5
+ // Parse Point to flat array
6
+ function parsePoint(geometry) {
7
+ const xy = geometry.xyArray();
8
+ const z = geometry.zArray();
9
+ const positions = blitArrays(xy, z);
10
+ return { positions };
11
+ }
12
+ function parseLines(geometry) {
13
+ const xy = geometry.xyArray();
14
+ const z = geometry.zArray();
15
+ const positions = blitArrays(xy, z);
16
+ // If endsArray is null, a single LineString. Otherwise, contains the end
17
+ // indices of each part of the MultiLineString. geometry.endsArray() omits the
18
+ // initial 0 that we have in our internal format.
19
+ const ends = (geometry.endsArray() && Array.from(geometry.endsArray())) || [xy.length / 2];
20
+ ends.unshift(0);
21
+ const pathIndices = { value: new Uint16Array(ends), size: 1 };
22
+ return {
23
+ positions,
24
+ pathIndices
25
+ };
26
+ }
27
+ function parsePolygons(geometry) {
28
+ const xy = geometry.xyArray();
29
+ const z = geometry.zArray();
30
+ const positions = blitArrays(xy, z);
31
+ // If endsArray is null, a simple Polygon with no inner rings. Otherwise,
32
+ // contains the end indices of each ring of the Polygon. geometry.endsArray()
33
+ // omits the initial 0 that we have in our internal format.
34
+ const ends = (geometry.endsArray() && Array.from(geometry.endsArray())) || [xy.length / 2];
35
+ ends.unshift(0);
36
+ const primitivePolygonIndices = { value: new Uint16Array(ends), size: 1 };
37
+ const polygonIndices = { value: new Uint16Array([0, xy.length / 2]), size: 1 };
38
+ return {
39
+ positions,
40
+ primitivePolygonIndices,
41
+ polygonIndices
42
+ };
43
+ }
44
+ // eslint-disable-next-line max-statements
45
+ function parseMultiPolygons(geometry) {
46
+ // Create arrays for each geometry part, then concatenate
47
+ const parsedParts = [];
48
+ let nPositions = 0;
49
+ let nPrimitivePolygonIndices = 1;
50
+ let nPolygonIndices = 1;
51
+ for (let i = 0; i < geometry.partsLength(); i++) {
52
+ const part = geometry.parts(i);
53
+ const polygon = parsePolygons(part);
54
+ nPositions += polygon.positions.value.length;
55
+ nPrimitivePolygonIndices += polygon.primitivePolygonIndices.value.length - 1;
56
+ nPolygonIndices += polygon.polygonIndices.value.length - 1;
57
+ parsedParts.push(polygon);
58
+ }
59
+ const concatPositions = new Float64Array(nPositions);
60
+ const concatPrimitivePolygonIndices = new Uint32Array(nPrimitivePolygonIndices);
61
+ const concatPolygonIndices = new Uint32Array(nPolygonIndices);
62
+ let positionCounter = 0;
63
+ let primitivePolygonIndicesCounter = 1;
64
+ let polygonIndicesCounter = 1;
65
+ // Assumes all parts of the multipolygon have the same size
66
+ const positionSize = parsedParts[0].positions.size;
67
+ for (const parsedPart of parsedParts) {
68
+ concatPositions.set(parsedPart.positions.value, positionCounter * positionSize);
69
+ // For indices, need to add positionCounter so that position indices are
70
+ // correct in the concatenated positions
71
+ concatPrimitivePolygonIndices.set(
72
+ // eslint-disable-next-line
73
+ parsedPart.primitivePolygonIndices.value.subarray(1).map((x) => x + positionCounter), primitivePolygonIndicesCounter);
74
+ concatPolygonIndices.set(
75
+ // eslint-disable-next-line
76
+ parsedPart.polygonIndices.value.subarray(1).map((x) => x + positionCounter), polygonIndicesCounter);
77
+ positionCounter += parsedPart.positions.value.length / positionSize;
78
+ primitivePolygonIndicesCounter += parsedPart.primitivePolygonIndices.value.length - 1;
79
+ polygonIndicesCounter += parsedPart.polygonIndices.value.length - 1;
80
+ }
81
+ return {
82
+ positions: { value: concatPositions, size: positionSize },
83
+ primitivePolygonIndices: { value: concatPrimitivePolygonIndices, size: 1 },
84
+ polygonIndices: { value: concatPolygonIndices, size: 1 }
85
+ };
86
+ }
87
+ // Combine xy and z arrays
88
+ function blitArrays(xy, z) {
89
+ if (!z) {
90
+ return { value: xy, size: 2 };
91
+ }
92
+ if (z.length * 2 !== xy.length) {
93
+ throw new Error('Z array must be half XY array\'s length');
94
+ }
95
+ const totalLength = xy.length + z.length;
96
+ const xyz = new Float64Array(totalLength);
97
+ for (let i = 0; i < xy.length / 2; i++) {
98
+ xyz[i * 3 + 0] = xy[i * 2 + 0];
99
+ xyz[i * 3 + 1] = xy[i * 2 + 1];
100
+ xyz[i * 3 + 2] = z[i];
101
+ }
102
+ return { value: xyz, size: 3 };
103
+ }
104
+ function fromGeometry(geometry, type) {
105
+ switch (type) {
106
+ case header_generated_1.GeometryType.Point:
107
+ case header_generated_1.GeometryType.MultiPoint:
108
+ return parsePoint(geometry);
109
+ case header_generated_1.GeometryType.LineString:
110
+ case header_generated_1.GeometryType.MultiLineString:
111
+ return parseLines(geometry);
112
+ case header_generated_1.GeometryType.Polygon:
113
+ return parsePolygons(geometry);
114
+ case header_generated_1.GeometryType.MultiPolygon:
115
+ return parseMultiPolygons(geometry);
116
+ default:
117
+ throw new Error(`Unimplemented geometry type: ${type}`);
118
+ }
119
+ }
120
+ exports.fromGeometry = fromGeometry;
@@ -1,3 +1,3 @@
1
- export default function parseFlatGeobuf(input: any, options: any): any;
2
- export declare function parseFlatGeobufInBatches(stream: any, options: any): any;
1
+ export declare function parseFlatGeobuf(arrayBuffer: any, options: any): any;
2
+ export declare function parseFlatGeobufInBatches(stream: any, options: any): any[] | AsyncGenerator<import("flatgeobuf/lib/cjs/generic/feature").IFeature, any, unknown> | AsyncGenerator<any, void, unknown>;
3
3
  //# sourceMappingURL=parse-flatgeobuf.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parse-flatgeobuf.d.ts","sourceRoot":"","sources":["../../src/lib/parse-flatgeobuf.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,KAAK,KAAA,EAAE,OAAO,KAAA,OAQrD;AAQD,wBAAgB,wBAAwB,CAAC,MAAM,KAAA,EAAE,OAAO,KAAA,OAGvD"}
1
+ {"version":3,"file":"parse-flatgeobuf.d.ts","sourceRoot":"","sources":["../../src/lib/parse-flatgeobuf.ts"],"names":[],"mappings":"AAgCA,wBAAgB,eAAe,CAAC,WAAW,KAAA,EAAE,OAAO,KAAA,OAUnD;AA6CD,wBAAgB,wBAAwB,CAAC,MAAM,KAAA,EAAE,OAAO,KAAA,oIAMvD"}
@@ -1,31 +1,114 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseFlatGeobufInBatches = void 0;
4
- // import {deserialize} from 'flatgeobuf/lib/geojson/featurecollection';
5
- const flatgeobuf_geojson_min_1 = require("flatgeobuf/dist/flatgeobuf-geojson.min");
3
+ exports.parseFlatGeobufInBatches = exports.parseFlatGeobuf = void 0;
4
+ // @ts-nocheck
5
+ const proj4_1 = require("@math.gl/proj4");
6
+ const gis_1 = require("@loaders.gl/gis");
7
+ const geojson_1 = require("flatgeobuf/lib/cjs/geojson");
8
+ const generic_1 = require("flatgeobuf/lib/cjs/generic");
9
+ const feature_1 = require("flatgeobuf/lib/cjs/generic/feature");
10
+ const binary_geometries_1 = require("./binary-geometries");
11
+ // TODO: reproject binary features
12
+ function binaryFromFeature(feature, header) {
13
+ const geometry = feature.geometry();
14
+ // FlatGeobuf files can only hold a single geometry type per file, otherwise
15
+ // GeometryType is GeometryCollection
16
+ // I believe geometry.type() is null (0) except when the geometry type isn't
17
+ // known in the header?
18
+ const geometryType = header.geometryType || geometry.type();
19
+ const parsedGeometry = (0, binary_geometries_1.fromGeometry)(geometry, geometryType);
20
+ parsedGeometry.properties = (0, feature_1.parseProperties)(feature, header.columns);
21
+ // TODO: wrap binary data either in points, lines, or polygons key
22
+ return parsedGeometry;
23
+ }
6
24
  /*
7
25
  * Parse FlatGeobuf arrayBuffer and return GeoJSON.
8
26
  *
9
- * @param {arrayBuffer} _ A FlatGeobuf arrayBuffer
10
- * @return {?Object} A GeoJSON geometry object
27
+ * @param arrayBuffer A FlatGeobuf arrayBuffer
28
+ * @return A GeoJSON geometry object
11
29
  */
12
- function parseFlatGeobuf(input, options) {
13
- if (input.byteLength === 0) {
30
+ function parseFlatGeobuf(arrayBuffer, options) {
31
+ if (arrayBuffer.byteLength === 0) {
14
32
  return [];
15
33
  }
16
- const arr = new Uint8Array(input);
17
- const { features } = (0, flatgeobuf_geojson_min_1.deserialize)(arr);
34
+ if (options && options.gis && options.gis.format === 'binary') {
35
+ return parseFlatGeobufToBinary(arrayBuffer, options);
36
+ }
37
+ return parseFlatGeobufToGeoJSON(arrayBuffer, options);
38
+ }
39
+ exports.parseFlatGeobuf = parseFlatGeobuf;
40
+ function parseFlatGeobufToBinary(arrayBuffer, options) {
41
+ // TODO: reproject binary features
42
+ // const {reproject = false, _targetCrs = 'WGS84'} = (options && options.gis) || {};
43
+ const arr = new Uint8Array(arrayBuffer);
44
+ return (0, generic_1.deserialize)(arr, binaryFromFeature);
45
+ }
46
+ function parseFlatGeobufToGeoJSON(arrayBuffer, options) {
47
+ const { reproject = false, _targetCrs = 'WGS84' } = (options && options.gis) || {};
48
+ const arr = new Uint8Array(arrayBuffer);
49
+ let headerMeta;
50
+ const { features } = (0, geojson_1.deserialize)(arr, false, (header) => {
51
+ headerMeta = header;
52
+ });
53
+ const crs = headerMeta && headerMeta.crs;
54
+ let projection;
55
+ if (reproject && crs) {
56
+ // Constructing the projection may fail for some invalid WKT strings
57
+ try {
58
+ projection = new proj4_1.Proj4Projection({ from: crs.wkt, to: _targetCrs });
59
+ }
60
+ catch (e) {
61
+ // no op
62
+ }
63
+ }
64
+ if (projection) {
65
+ return (0, gis_1.transformGeoJsonCoords)(features, (coords) => projection.project(coords));
66
+ }
18
67
  return features;
19
68
  }
20
- exports.default = parseFlatGeobuf;
21
69
  /*
22
70
  * Parse FlatGeobuf arrayBuffer and return GeoJSON.
23
71
  *
24
72
  * @param {ReadableStream} _ A FlatGeobuf arrayBuffer
25
73
  * @return A GeoJSON geometry object iterator
26
74
  */
75
+ // eslint-disable-next-line complexity
27
76
  function parseFlatGeobufInBatches(stream, options) {
28
- const iterator = (0, flatgeobuf_geojson_min_1.deserializeStream)(stream);
29
- return iterator;
77
+ if (options && options.gis && options.gis.format === 'binary') {
78
+ return parseFlatGeobufInBatchesToBinary(stream, options);
79
+ }
80
+ return parseFlatGeobufInBatchesToGeoJSON(stream, options);
30
81
  }
31
82
  exports.parseFlatGeobufInBatches = parseFlatGeobufInBatches;
83
+ function parseFlatGeobufInBatchesToBinary(stream, options) {
84
+ // TODO: reproject binary streaming features
85
+ // const {reproject = false, _targetCrs = 'WGS84'} = (options && options.gis) || {};
86
+ const iterator = (0, generic_1.deserialize)(stream, binaryFromFeature);
87
+ return iterator;
88
+ }
89
+ // eslint-disable-next-line complexity
90
+ async function* parseFlatGeobufInBatchesToGeoJSON(stream, options) {
91
+ const { reproject = false, _targetCrs = 'WGS84' } = (options && options.gis) || {};
92
+ let headerMeta;
93
+ const iterator = (0, geojson_1.deserialize)(stream, false, (header) => {
94
+ headerMeta = header;
95
+ });
96
+ let projection;
97
+ let firstRecord = true;
98
+ for await (const feature of iterator) {
99
+ if (firstRecord) {
100
+ const crs = headerMeta && headerMeta.crs;
101
+ if (reproject && crs) {
102
+ projection = new proj4_1.Proj4Projection({ from: crs.wkt, to: _targetCrs });
103
+ }
104
+ firstRecord = false;
105
+ }
106
+ if (reproject && projection) {
107
+ // eslint-disable-next-line
108
+ yield (0, gis_1.transformGeoJsonCoords)([feature], (coords) => projection.project(coords));
109
+ }
110
+ else {
111
+ yield feature;
112
+ }
113
+ }
114
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@loaders.gl/flatgeobuf",
3
3
  "description": "Loader for FlatGeobuf",
4
- "version": "3.1.0-beta.5",
4
+ "version": "3.1.2",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -28,15 +28,14 @@
28
28
  ],
29
29
  "scripts": {
30
30
  "pre-build": "npm run build-worker && npm run build-worker --env.dev && npm run build-bundle",
31
- "build-bundle": "esbuild src/bundle.ts --bundle --outfile=dist/bundle.js",
31
+ "build-bundle": "esbuild src/bundle.ts --bundle --outfile=dist/dist.min.js",
32
32
  "build-worker": "esbuild src/workers/flatgeobuf-worker.ts --bundle --outfile=dist/flatgeobuf-worker.js"
33
33
  },
34
34
  "dependencies": {
35
- "@loaders.gl/loader-utils": "3.1.0-beta.5",
36
- "flatgeobuf": "~3.1.0"
35
+ "@loaders.gl/gis": "4.0.0-alpha.1",
36
+ "@loaders.gl/loader-utils": "3.1.2",
37
+ "@math.gl/proj4": "^3.3.1",
38
+ "flatgeobuf": "3.6.5"
37
39
  },
38
- "devDependencies": {
39
- "esm": "^3.2.25"
40
- },
41
- "gitHead": "5d66468457cc878d2dbff3d7807d737ceb181c9a"
40
+ "gitHead": "5c25bb71a2ac8558ecedf2256cc925427b2a0506"
42
41
  }
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type {LoaderWithParser} from '@loaders.gl/loader-utils';
2
2
  import {FlatGeobufLoader as FlatGeobufWorkerLoader} from './flatgeobuf-loader';
3
- import parseFlatGeobuf, {parseFlatGeobufInBatches} from './lib/parse-flatgeobuf';
3
+ import {parseFlatGeobuf, parseFlatGeobufInBatches} from './lib/parse-flatgeobuf';
4
4
 
5
5
  export {FlatGeobufWorkerLoader};
6
6
 
@@ -0,0 +1,144 @@
1
+ import {GeometryType} from 'flatgeobuf/lib/cjs/header_generated';
2
+
3
+ // Parse Point to flat array
4
+ function parsePoint(geometry) {
5
+ const xy = geometry.xyArray();
6
+ const z = geometry.zArray();
7
+ const positions = blitArrays(xy, z);
8
+ return {positions};
9
+ }
10
+
11
+ function parseLines(geometry) {
12
+ const xy = geometry.xyArray();
13
+ const z = geometry.zArray();
14
+ const positions = blitArrays(xy, z);
15
+
16
+ // If endsArray is null, a single LineString. Otherwise, contains the end
17
+ // indices of each part of the MultiLineString. geometry.endsArray() omits the
18
+ // initial 0 that we have in our internal format.
19
+ const ends = (geometry.endsArray() && Array.from(geometry.endsArray())) || [xy.length / 2];
20
+ ends.unshift(0);
21
+
22
+ const pathIndices = {value: new Uint16Array(ends), size: 1};
23
+
24
+ return {
25
+ positions,
26
+ pathIndices
27
+ };
28
+ }
29
+
30
+ function parsePolygons(geometry) {
31
+ const xy = geometry.xyArray();
32
+ const z = geometry.zArray();
33
+ const positions = blitArrays(xy, z);
34
+
35
+ // If endsArray is null, a simple Polygon with no inner rings. Otherwise,
36
+ // contains the end indices of each ring of the Polygon. geometry.endsArray()
37
+ // omits the initial 0 that we have in our internal format.
38
+ const ends = (geometry.endsArray() && Array.from(geometry.endsArray())) || [xy.length / 2];
39
+ ends.unshift(0);
40
+
41
+ const primitivePolygonIndices = {value: new Uint16Array(ends), size: 1};
42
+ const polygonIndices = {value: new Uint16Array([0, xy.length / 2]), size: 1};
43
+
44
+ return {
45
+ positions,
46
+ primitivePolygonIndices,
47
+ polygonIndices
48
+ };
49
+ }
50
+
51
+ // eslint-disable-next-line max-statements
52
+ function parseMultiPolygons(geometry) {
53
+ // Create arrays for each geometry part, then concatenate
54
+ const parsedParts: any[] = [];
55
+ let nPositions = 0;
56
+ let nPrimitivePolygonIndices = 1;
57
+ let nPolygonIndices = 1;
58
+
59
+ for (let i = 0; i < geometry.partsLength(); i++) {
60
+ const part = geometry.parts(i);
61
+ const polygon = parsePolygons(part);
62
+
63
+ nPositions += polygon.positions.value.length;
64
+ nPrimitivePolygonIndices += polygon.primitivePolygonIndices.value.length - 1;
65
+ nPolygonIndices += polygon.polygonIndices.value.length - 1;
66
+
67
+ parsedParts.push(polygon);
68
+ }
69
+
70
+ const concatPositions = new Float64Array(nPositions);
71
+ const concatPrimitivePolygonIndices = new Uint32Array(nPrimitivePolygonIndices);
72
+ const concatPolygonIndices = new Uint32Array(nPolygonIndices);
73
+
74
+ let positionCounter = 0;
75
+ let primitivePolygonIndicesCounter = 1;
76
+ let polygonIndicesCounter = 1;
77
+
78
+ // Assumes all parts of the multipolygon have the same size
79
+ const positionSize = parsedParts[0].positions.size;
80
+
81
+ for (const parsedPart of parsedParts) {
82
+ concatPositions.set(parsedPart.positions.value, positionCounter * positionSize);
83
+
84
+ // For indices, need to add positionCounter so that position indices are
85
+ // correct in the concatenated positions
86
+ concatPrimitivePolygonIndices.set(
87
+ // eslint-disable-next-line
88
+ parsedPart.primitivePolygonIndices.value.subarray(1).map((x) => x + positionCounter),
89
+ primitivePolygonIndicesCounter
90
+ );
91
+ concatPolygonIndices.set(
92
+ // eslint-disable-next-line
93
+ parsedPart.polygonIndices.value.subarray(1).map((x) => x + positionCounter),
94
+ polygonIndicesCounter
95
+ );
96
+
97
+ positionCounter += parsedPart.positions.value.length / positionSize;
98
+ primitivePolygonIndicesCounter += parsedPart.primitivePolygonIndices.value.length - 1;
99
+ polygonIndicesCounter += parsedPart.polygonIndices.value.length - 1;
100
+ }
101
+
102
+ return {
103
+ positions: {value: concatPositions, size: positionSize},
104
+ primitivePolygonIndices: {value: concatPrimitivePolygonIndices, size: 1},
105
+ polygonIndices: {value: concatPolygonIndices, size: 1}
106
+ };
107
+ }
108
+
109
+ // Combine xy and z arrays
110
+ function blitArrays(xy, z) {
111
+ if (!z) {
112
+ return {value: xy, size: 2};
113
+ }
114
+
115
+ if (z.length * 2 !== xy.length) {
116
+ throw new Error('Z array must be half XY array\'s length');
117
+ }
118
+ const totalLength = xy.length + z.length;
119
+
120
+ const xyz = new Float64Array(totalLength);
121
+ for (let i = 0; i < xy.length / 2; i++) {
122
+ xyz[i * 3 + 0] = xy[i * 2 + 0];
123
+ xyz[i * 3 + 1] = xy[i * 2 + 1];
124
+ xyz[i * 3 + 2] = z[i];
125
+ }
126
+ return {value: xyz, size: 3};
127
+ }
128
+
129
+ export function fromGeometry(geometry, type) {
130
+ switch (type) {
131
+ case GeometryType.Point:
132
+ case GeometryType.MultiPoint:
133
+ return parsePoint(geometry);
134
+ case GeometryType.LineString:
135
+ case GeometryType.MultiLineString:
136
+ return parseLines(geometry);
137
+ case GeometryType.Polygon:
138
+ return parsePolygons(geometry);
139
+ case GeometryType.MultiPolygon:
140
+ return parseMultiPolygons(geometry);
141
+ default:
142
+ throw new Error(`Unimplemented geometry type: ${type}`);
143
+ }
144
+ }
@@ -1,19 +1,80 @@
1
- // import {deserialize} from 'flatgeobuf/lib/geojson/featurecollection';
2
- import {deserialize, deserializeStream} from 'flatgeobuf/dist/flatgeobuf-geojson.min';
1
+ // @ts-nocheck
2
+ import {Proj4Projection} from '@math.gl/proj4';
3
+ import {transformGeoJsonCoords} from '@loaders.gl/gis';
4
+
5
+ import {deserialize as deserializeGeoJson} from 'flatgeobuf/lib/cjs/geojson';
6
+ import {deserialize as deserializeGeneric} from 'flatgeobuf/lib/cjs/generic';
7
+ import {parseProperties as parsePropertiesBinary} from 'flatgeobuf/lib/cjs/generic/feature';
8
+
9
+ import {fromGeometry as binaryFromGeometry} from './binary-geometries';
10
+
11
+ // TODO: reproject binary features
12
+ function binaryFromFeature(feature, header) {
13
+ const geometry = feature.geometry();
14
+
15
+ // FlatGeobuf files can only hold a single geometry type per file, otherwise
16
+ // GeometryType is GeometryCollection
17
+ // I believe geometry.type() is null (0) except when the geometry type isn't
18
+ // known in the header?
19
+ const geometryType = header.geometryType || geometry.type();
20
+ const parsedGeometry = binaryFromGeometry(geometry, geometryType);
21
+ parsedGeometry.properties = parsePropertiesBinary(feature, header.columns);
22
+
23
+ // TODO: wrap binary data either in points, lines, or polygons key
24
+ return parsedGeometry;
25
+ }
3
26
 
4
27
  /*
5
28
  * Parse FlatGeobuf arrayBuffer and return GeoJSON.
6
29
  *
7
- * @param {arrayBuffer} _ A FlatGeobuf arrayBuffer
8
- * @return {?Object} A GeoJSON geometry object
30
+ * @param arrayBuffer A FlatGeobuf arrayBuffer
31
+ * @return A GeoJSON geometry object
9
32
  */
10
- export default function parseFlatGeobuf(input, options) {
11
- if (input.byteLength === 0) {
33
+ export function parseFlatGeobuf(arrayBuffer, options) {
34
+ if (arrayBuffer.byteLength === 0) {
12
35
  return [];
13
36
  }
14
37
 
15
- const arr = new Uint8Array(input);
16
- const {features} = deserialize(arr);
38
+ if (options && options.gis && options.gis.format === 'binary') {
39
+ return parseFlatGeobufToBinary(arrayBuffer, options);
40
+ }
41
+
42
+ return parseFlatGeobufToGeoJSON(arrayBuffer, options);
43
+ }
44
+
45
+ function parseFlatGeobufToBinary(arrayBuffer, options) {
46
+ // TODO: reproject binary features
47
+ // const {reproject = false, _targetCrs = 'WGS84'} = (options && options.gis) || {};
48
+
49
+ const arr = new Uint8Array(arrayBuffer);
50
+ return deserializeGeneric(arr, binaryFromFeature);
51
+ }
52
+
53
+ function parseFlatGeobufToGeoJSON(arrayBuffer, options) {
54
+ const {reproject = false, _targetCrs = 'WGS84'} = (options && options.gis) || {};
55
+
56
+ const arr = new Uint8Array(arrayBuffer);
57
+
58
+ let headerMeta;
59
+ const {features} = deserializeGeoJson(arr, false, (header) => {
60
+ headerMeta = header;
61
+ });
62
+
63
+ const crs = headerMeta && headerMeta.crs;
64
+ let projection;
65
+ if (reproject && crs) {
66
+ // Constructing the projection may fail for some invalid WKT strings
67
+ try {
68
+ projection = new Proj4Projection({from: crs.wkt, to: _targetCrs});
69
+ } catch (e) {
70
+ // no op
71
+ }
72
+ }
73
+
74
+ if (projection) {
75
+ return transformGeoJsonCoords(features, (coords) => projection.project(coords));
76
+ }
77
+
17
78
  return features;
18
79
  }
19
80
 
@@ -23,7 +84,49 @@ export default function parseFlatGeobuf(input, options) {
23
84
  * @param {ReadableStream} _ A FlatGeobuf arrayBuffer
24
85
  * @return A GeoJSON geometry object iterator
25
86
  */
87
+ // eslint-disable-next-line complexity
26
88
  export function parseFlatGeobufInBatches(stream, options) {
27
- const iterator = deserializeStream(stream);
89
+ if (options && options.gis && options.gis.format === 'binary') {
90
+ return parseFlatGeobufInBatchesToBinary(stream, options);
91
+ }
92
+
93
+ return parseFlatGeobufInBatchesToGeoJSON(stream, options);
94
+ }
95
+
96
+ function parseFlatGeobufInBatchesToBinary(stream, options) {
97
+ // TODO: reproject binary streaming features
98
+ // const {reproject = false, _targetCrs = 'WGS84'} = (options && options.gis) || {};
99
+
100
+ const iterator = deserializeGeneric(stream, binaryFromFeature);
28
101
  return iterator;
29
102
  }
103
+
104
+ // eslint-disable-next-line complexity
105
+ async function* parseFlatGeobufInBatchesToGeoJSON(stream, options) {
106
+ const {reproject = false, _targetCrs = 'WGS84'} = (options && options.gis) || {};
107
+
108
+ let headerMeta;
109
+ const iterator = deserializeGeoJson(stream, false, (header) => {
110
+ headerMeta = header;
111
+ });
112
+
113
+ let projection;
114
+ let firstRecord = true;
115
+ for await (const feature of iterator) {
116
+ if (firstRecord) {
117
+ const crs = headerMeta && headerMeta.crs;
118
+ if (reproject && crs) {
119
+ projection = new Proj4Projection({from: crs.wkt, to: _targetCrs});
120
+ }
121
+
122
+ firstRecord = false;
123
+ }
124
+
125
+ if (reproject && projection) {
126
+ // eslint-disable-next-line
127
+ yield transformGeoJsonCoords([feature], (coords) => projection.project(coords));
128
+ } else {
129
+ yield feature;
130
+ }
131
+ }
132
+ }