@reearth/core 0.0.3 → 0.0.4
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/core.js +12486 -9418
- package/dist/core.umd.cjs +76 -73
- package/package.json +4 -2
- package/src/.DS_Store +0 -0
- package/src/Map/utils.ts +8 -2
- package/src/engines/Cesium/.DS_Store +0 -0
- package/src/engines/Cesium/Feature/.DS_Store +0 -0
- package/src/engines/Cesium/core/.DS_Store +0 -0
- package/src/engines/Cesium/hooks.ts +6 -0
- package/src/engines/Cesium/type.d.ts +0 -1
- package/src/engines/Cesium/utils/polygon.ts +2 -2
- package/src/mantle/atoms/compute.ts +2 -2
- package/src/mantle/data/gpx.ts +1 -1
- package/src/mantle/data/shapefile/index.ts +51 -0
- package/src/mantle/data/shapefile/parseDbf.ts +85 -0
- package/src/mantle/data/shapefile/parseShp.ts +459 -0
- package/src/mantle/data/shapefile/parseZip.ts +64 -0
- package/src/mantle/evaluator/simple/expression/variableReplacer.ts +0 -2
- package/src/mantle/evaluator/simple/index.ts +0 -5
- package/src/mantle/evaluator/simple/utils.ts +0 -1
- package/src/test/utils.tsx +0 -2
- package/src/utils/.DS_Store +0 -0
- package/src/mantle/data/shapefile.ts +0 -232
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
GeometryObject,
|
|
3
|
+
Feature as GeoJSONFeature,
|
|
4
|
+
MultiPoint,
|
|
5
|
+
Polygon,
|
|
6
|
+
MultiLineString,
|
|
7
|
+
} from "geojson";
|
|
8
|
+
import proj4 from "proj4";
|
|
9
|
+
|
|
10
|
+
import { generateRandomString } from "../utils";
|
|
11
|
+
|
|
12
|
+
export function parseShp(
|
|
13
|
+
buffer: ArrayBuffer,
|
|
14
|
+
trans?: proj4.Converter | false,
|
|
15
|
+
): GeoJSONFeature<GeometryObject>[] {
|
|
16
|
+
const headers = parseHeader(buffer);
|
|
17
|
+
const parseFunc = getParseFunction(headers.shpCode, trans);
|
|
18
|
+
const rows = getRows(buffer, headers, parseFunc);
|
|
19
|
+
return rows;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function parseHeader(buffer: ArrayBuffer): {
|
|
23
|
+
length: number;
|
|
24
|
+
version: number;
|
|
25
|
+
shpCode: number;
|
|
26
|
+
bbox: number[];
|
|
27
|
+
} {
|
|
28
|
+
const view = new DataView(buffer, 0, 100);
|
|
29
|
+
return {
|
|
30
|
+
length: view.getInt32(6 << 2, false) << 1,
|
|
31
|
+
version: view.getInt32(7 << 2, true),
|
|
32
|
+
shpCode: view.getInt32(8 << 2, true),
|
|
33
|
+
bbox: [
|
|
34
|
+
view.getFloat64(9 << 2, true),
|
|
35
|
+
view.getFloat64(11 << 2, true),
|
|
36
|
+
view.getFloat64(13 << 2, true),
|
|
37
|
+
view.getFloat64(15 << 2, true),
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function makeParseCoord(
|
|
43
|
+
trans?: proj4.Converter | false,
|
|
44
|
+
): (data: DataView, offset: number) => number[] {
|
|
45
|
+
if (trans) {
|
|
46
|
+
return (data: DataView, offset: number) => {
|
|
47
|
+
const x = data.getFloat64(offset, true);
|
|
48
|
+
const y = data.getFloat64(offset + 8, true);
|
|
49
|
+
return trans.inverse([x, y]);
|
|
50
|
+
};
|
|
51
|
+
} else {
|
|
52
|
+
return (data: DataView, offset: number) => [
|
|
53
|
+
data.getFloat64(offset, true),
|
|
54
|
+
data.getFloat64(offset + 8, true),
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function getParseFunction(
|
|
60
|
+
shpCode: number,
|
|
61
|
+
trans?: proj4.Converter | false,
|
|
62
|
+
): (data: ArrayBuffer) => GeoJSONFeature<GeometryObject> | null {
|
|
63
|
+
const num = shpCode > 20 ? shpCode - 20 : shpCode;
|
|
64
|
+
const shpFuncObj: { [key: number]: keyof typeof parseFunctions } = {
|
|
65
|
+
1: "parsePoint",
|
|
66
|
+
3: "parsePolyline",
|
|
67
|
+
5: "parsePolygon",
|
|
68
|
+
8: "parseMultiPoint",
|
|
69
|
+
11: "parseZPoint",
|
|
70
|
+
13: "parseZPolyline",
|
|
71
|
+
15: "parseZPolygon",
|
|
72
|
+
};
|
|
73
|
+
const funcName = shpFuncObj[num];
|
|
74
|
+
if (!funcName) {
|
|
75
|
+
throw new Error("Unsupported shape type");
|
|
76
|
+
}
|
|
77
|
+
const parseCoord = makeParseCoord(trans);
|
|
78
|
+
|
|
79
|
+
switch (funcName) {
|
|
80
|
+
case "parsePoint":
|
|
81
|
+
case "parseZPoint":
|
|
82
|
+
case "parseMultiPoint":
|
|
83
|
+
case "parsePolyline":
|
|
84
|
+
case "parseZPolyline":
|
|
85
|
+
case "parsePolygon":
|
|
86
|
+
case "parseZPolygon":
|
|
87
|
+
return (data: ArrayBuffer) => parseFunctions[funcName](new DataView(data), parseCoord);
|
|
88
|
+
case "parsePointArray":
|
|
89
|
+
return (data: ArrayBuffer) =>
|
|
90
|
+
parseFunctions[funcName](
|
|
91
|
+
new DataView(data),
|
|
92
|
+
0,
|
|
93
|
+
new DataView(data).getInt32(32, true),
|
|
94
|
+
parseCoord,
|
|
95
|
+
);
|
|
96
|
+
case "parseArrayGroup":
|
|
97
|
+
return (data: ArrayBuffer) =>
|
|
98
|
+
parseFunctions[funcName](
|
|
99
|
+
new DataView(data),
|
|
100
|
+
44,
|
|
101
|
+
40,
|
|
102
|
+
new DataView(data).getInt32(32, true),
|
|
103
|
+
new DataView(data).getInt32(36, true),
|
|
104
|
+
parseCoord,
|
|
105
|
+
);
|
|
106
|
+
default:
|
|
107
|
+
throw new Error("Unsupported shape type");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function getRows(
|
|
112
|
+
buffer: ArrayBuffer,
|
|
113
|
+
headers: ReturnType<typeof parseHeader>,
|
|
114
|
+
parseFunc: ReturnType<typeof getParseFunction>,
|
|
115
|
+
): GeoJSONFeature<GeometryObject>[] {
|
|
116
|
+
const rows: GeoJSONFeature<GeometryObject>[] = [];
|
|
117
|
+
let offset = 100;
|
|
118
|
+
const bufferLength = buffer.byteLength;
|
|
119
|
+
while (offset + 8 <= bufferLength) {
|
|
120
|
+
const record = getRow(buffer, offset, bufferLength);
|
|
121
|
+
if (!record) {
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
offset += 8 + record.len;
|
|
125
|
+
const feature = parseFunc(record.data);
|
|
126
|
+
if (feature) {
|
|
127
|
+
feature.id = generateRandomString(12);
|
|
128
|
+
rows.push(feature);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return rows;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function getRow(
|
|
135
|
+
buffer: ArrayBuffer,
|
|
136
|
+
offset: number,
|
|
137
|
+
bufferLength: number,
|
|
138
|
+
):
|
|
139
|
+
| {
|
|
140
|
+
id: number;
|
|
141
|
+
len: number;
|
|
142
|
+
data: ArrayBuffer;
|
|
143
|
+
type: number;
|
|
144
|
+
}
|
|
145
|
+
| undefined {
|
|
146
|
+
const view = new DataView(buffer, offset, 12);
|
|
147
|
+
const len = view.getInt32(4, false) << 1;
|
|
148
|
+
const id = view.getInt32(0, false);
|
|
149
|
+
if (len === 0) {
|
|
150
|
+
return {
|
|
151
|
+
id,
|
|
152
|
+
len,
|
|
153
|
+
data: new ArrayBuffer(0),
|
|
154
|
+
type: 0,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (offset + len + 8 > bufferLength) {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
id,
|
|
162
|
+
len,
|
|
163
|
+
data: buffer.slice(offset + 12, offset + len + 8),
|
|
164
|
+
type: view.getInt32(8, true),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const parseFunctions = {
|
|
169
|
+
parsePoint(
|
|
170
|
+
data: DataView,
|
|
171
|
+
parseCoord: ReturnType<typeof makeParseCoord>,
|
|
172
|
+
): GeoJSONFeature<GeometryObject> {
|
|
173
|
+
return {
|
|
174
|
+
type: "Feature",
|
|
175
|
+
geometry: {
|
|
176
|
+
type: "Point",
|
|
177
|
+
coordinates: parseCoord(data, 0),
|
|
178
|
+
},
|
|
179
|
+
properties: {},
|
|
180
|
+
};
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
parseZPoint(
|
|
184
|
+
data: DataView,
|
|
185
|
+
parseCoord: ReturnType<typeof makeParseCoord>,
|
|
186
|
+
): GeoJSONFeature<GeometryObject> {
|
|
187
|
+
const pointXY = parseFunctions.parsePoint(data, parseCoord);
|
|
188
|
+
(pointXY.geometry as any).coordinates.push(data.getFloat64(16, true));
|
|
189
|
+
return pointXY;
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
parsePointArray(
|
|
193
|
+
data: DataView,
|
|
194
|
+
offset: number,
|
|
195
|
+
num: number,
|
|
196
|
+
parseCoord: ReturnType<typeof makeParseCoord>,
|
|
197
|
+
): GeoJSONFeature<GeometryObject> {
|
|
198
|
+
const coordinates: number[][] = [];
|
|
199
|
+
for (let i = 0; i < num; i++) {
|
|
200
|
+
coordinates.push(parseCoord(data, offset));
|
|
201
|
+
offset += 16;
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
type: "Feature",
|
|
205
|
+
geometry: {
|
|
206
|
+
type: "MultiPoint",
|
|
207
|
+
coordinates,
|
|
208
|
+
},
|
|
209
|
+
properties: {},
|
|
210
|
+
};
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
parseZPointArray(
|
|
214
|
+
data: DataView,
|
|
215
|
+
zOffset: number,
|
|
216
|
+
num: number,
|
|
217
|
+
coordinates: number[][],
|
|
218
|
+
): number[][] {
|
|
219
|
+
for (let i = 0; i < num; i++) {
|
|
220
|
+
coordinates[i].push(data.getFloat64(zOffset, true));
|
|
221
|
+
zOffset += 8;
|
|
222
|
+
}
|
|
223
|
+
return coordinates;
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
parseArrayGroup(
|
|
227
|
+
data: DataView,
|
|
228
|
+
offset: number,
|
|
229
|
+
partOffset: number,
|
|
230
|
+
num: number,
|
|
231
|
+
tot: number,
|
|
232
|
+
parseCoord: ReturnType<typeof makeParseCoord>,
|
|
233
|
+
): GeoJSONFeature<Polygon> {
|
|
234
|
+
const coordinates: number[][][] = [];
|
|
235
|
+
let pointOffset = offset;
|
|
236
|
+
for (let i = 0; i < num; i++) {
|
|
237
|
+
const pointNum =
|
|
238
|
+
i === num - 1
|
|
239
|
+
? tot - data.getInt32(partOffset, true)
|
|
240
|
+
: data.getInt32(partOffset + 4, true) - data.getInt32(partOffset, true);
|
|
241
|
+
partOffset += 4;
|
|
242
|
+
if (pointNum === 0) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
const feature = parseFunctions.parsePointArray(data, pointOffset, pointNum, parseCoord);
|
|
246
|
+
coordinates.push((feature.geometry as MultiPoint).coordinates);
|
|
247
|
+
pointOffset += pointNum << 4;
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
type: "Feature",
|
|
251
|
+
geometry: {
|
|
252
|
+
type: "Polygon",
|
|
253
|
+
coordinates,
|
|
254
|
+
},
|
|
255
|
+
properties: {},
|
|
256
|
+
};
|
|
257
|
+
},
|
|
258
|
+
|
|
259
|
+
parseZArrayGroup(
|
|
260
|
+
data: DataView,
|
|
261
|
+
zOffset: number,
|
|
262
|
+
num: number,
|
|
263
|
+
coordinates: number[][][],
|
|
264
|
+
): number[][][] {
|
|
265
|
+
for (let i = 0; i < num; i++) {
|
|
266
|
+
coordinates[i] = parseFunctions.parseZPointArray(
|
|
267
|
+
data,
|
|
268
|
+
zOffset,
|
|
269
|
+
coordinates[i].length,
|
|
270
|
+
coordinates[i],
|
|
271
|
+
);
|
|
272
|
+
zOffset += coordinates[i].length << 3;
|
|
273
|
+
}
|
|
274
|
+
return coordinates;
|
|
275
|
+
},
|
|
276
|
+
|
|
277
|
+
parseMultiPoint(
|
|
278
|
+
data: DataView,
|
|
279
|
+
parseCoord: ReturnType<typeof makeParseCoord>,
|
|
280
|
+
): GeoJSONFeature<MultiPoint> {
|
|
281
|
+
const num = data.getInt32(32, true);
|
|
282
|
+
if (num === 0) {
|
|
283
|
+
return {
|
|
284
|
+
type: "Feature",
|
|
285
|
+
geometry: {
|
|
286
|
+
type: "MultiPoint",
|
|
287
|
+
coordinates: [],
|
|
288
|
+
},
|
|
289
|
+
properties: {},
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
const bounds = [parseCoord(data, 0), parseCoord(data, 16)];
|
|
293
|
+
const pointOffset = 36;
|
|
294
|
+
const feature = parseFunctions.parsePointArray(data, pointOffset, num, parseCoord);
|
|
295
|
+
const coordinates = (feature.geometry as MultiPoint).coordinates;
|
|
296
|
+
return {
|
|
297
|
+
type: "Feature",
|
|
298
|
+
geometry: {
|
|
299
|
+
type: "MultiPoint",
|
|
300
|
+
coordinates,
|
|
301
|
+
},
|
|
302
|
+
properties: {},
|
|
303
|
+
bbox: [bounds[0][0], bounds[0][1], bounds[1][0], bounds[1][1]],
|
|
304
|
+
};
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
parsePolyline(
|
|
308
|
+
data: DataView,
|
|
309
|
+
parseCoord: ReturnType<typeof makeParseCoord>,
|
|
310
|
+
): GeoJSONFeature<MultiLineString> {
|
|
311
|
+
const numParts = data.getInt32(32, true);
|
|
312
|
+
if (numParts === 0) {
|
|
313
|
+
return {
|
|
314
|
+
type: "Feature",
|
|
315
|
+
geometry: {
|
|
316
|
+
type: "MultiLineString",
|
|
317
|
+
coordinates: [],
|
|
318
|
+
},
|
|
319
|
+
properties: {},
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
const bounds = [parseCoord(data, 0), parseCoord(data, 16)];
|
|
323
|
+
const num = data.getInt32(36, true);
|
|
324
|
+
const partOffset = 40;
|
|
325
|
+
const pointOffset = 40 + (numParts << 2);
|
|
326
|
+
const feature = parseFunctions.parseArrayGroup(
|
|
327
|
+
data,
|
|
328
|
+
pointOffset,
|
|
329
|
+
partOffset,
|
|
330
|
+
numParts,
|
|
331
|
+
num,
|
|
332
|
+
parseCoord,
|
|
333
|
+
);
|
|
334
|
+
const coordinates = (feature.geometry as Polygon).coordinates;
|
|
335
|
+
return {
|
|
336
|
+
type: "Feature",
|
|
337
|
+
geometry: {
|
|
338
|
+
type: "MultiLineString",
|
|
339
|
+
coordinates,
|
|
340
|
+
},
|
|
341
|
+
properties: {},
|
|
342
|
+
bbox: [bounds[0][0], bounds[0][1], bounds[1][0], bounds[1][1]],
|
|
343
|
+
};
|
|
344
|
+
},
|
|
345
|
+
|
|
346
|
+
parseZPolyline(
|
|
347
|
+
data: DataView,
|
|
348
|
+
parseCoord: ReturnType<typeof makeParseCoord>,
|
|
349
|
+
): GeoJSONFeature<GeometryObject> {
|
|
350
|
+
const feature = parseFunctions.parsePolyline(data, parseCoord);
|
|
351
|
+
const numParts = data.getInt32(32, true);
|
|
352
|
+
const num = data.getInt32(36, true);
|
|
353
|
+
const zOffset = 56 + (num << 4) + (numParts << 2);
|
|
354
|
+
(feature.geometry as any).coordinates = parseFunctions.parseZArrayGroup(
|
|
355
|
+
data,
|
|
356
|
+
zOffset,
|
|
357
|
+
numParts,
|
|
358
|
+
(feature.geometry as any).coordinates,
|
|
359
|
+
);
|
|
360
|
+
return feature;
|
|
361
|
+
},
|
|
362
|
+
|
|
363
|
+
parsePolygon(
|
|
364
|
+
data: DataView,
|
|
365
|
+
parseCoord: ReturnType<typeof makeParseCoord>,
|
|
366
|
+
): GeoJSONFeature<GeometryObject> {
|
|
367
|
+
const feature = parseFunctions.parsePolyline(data, parseCoord);
|
|
368
|
+
(feature.geometry as any).type = "MultiPolygon";
|
|
369
|
+
(feature.geometry as any).coordinates = handleRings((feature.geometry as any).coordinates);
|
|
370
|
+
return feature;
|
|
371
|
+
},
|
|
372
|
+
|
|
373
|
+
parseZPolygon(
|
|
374
|
+
data: DataView,
|
|
375
|
+
parseCoord: ReturnType<typeof makeParseCoord>,
|
|
376
|
+
): GeoJSONFeature<GeometryObject> {
|
|
377
|
+
const feature = parseFunctions.parseZPolyline(data, parseCoord);
|
|
378
|
+
(feature.geometry as any).type = "MultiPolygon";
|
|
379
|
+
(feature.geometry as any).coordinates = handleRings((feature.geometry as any).coordinates);
|
|
380
|
+
return feature;
|
|
381
|
+
},
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
function handleRings(rings: number[][][]): number[][][][] {
|
|
385
|
+
const clockwiseRings: {
|
|
386
|
+
ring: number[][];
|
|
387
|
+
bbox: number[];
|
|
388
|
+
children: number[][][];
|
|
389
|
+
}[] = [];
|
|
390
|
+
const counterClockwiseRings: {
|
|
391
|
+
ring: number[][];
|
|
392
|
+
bbox: number[];
|
|
393
|
+
children: number[][][];
|
|
394
|
+
}[] = [];
|
|
395
|
+
|
|
396
|
+
for (const ring of rings) {
|
|
397
|
+
const { ring: coordinates, bbox, clockwise } = isClockwise(ring);
|
|
398
|
+
if (clockwise) {
|
|
399
|
+
clockwiseRings.push({ ring: coordinates, bbox, children: [] });
|
|
400
|
+
} else {
|
|
401
|
+
counterClockwiseRings.push({ ring: coordinates, bbox, children: [] });
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
for (const counterClockwiseRing of counterClockwiseRings) {
|
|
406
|
+
let parent: (typeof clockwiseRings)[number] | undefined;
|
|
407
|
+
for (const clockwiseRing of clockwiseRings) {
|
|
408
|
+
if (contains(clockwiseRing.bbox, counterClockwiseRing.bbox)) {
|
|
409
|
+
parent = clockwiseRing;
|
|
410
|
+
break;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
if (parent) {
|
|
414
|
+
parent.children.push(counterClockwiseRing.ring);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return clockwiseRings.map(({ ring, children }) => [ring, ...children]);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function isClockwise(ring: number[][]): { ring: number[][]; bbox: number[]; clockwise: boolean } {
|
|
422
|
+
const [firstPoint, ...otherPoints] = ring;
|
|
423
|
+
let minX = firstPoint[0];
|
|
424
|
+
let minY = firstPoint[1];
|
|
425
|
+
let maxX = firstPoint[0];
|
|
426
|
+
let maxY = firstPoint[1];
|
|
427
|
+
|
|
428
|
+
let signedArea = 0;
|
|
429
|
+
let previousPoint = firstPoint;
|
|
430
|
+
|
|
431
|
+
for (const point of otherPoints) {
|
|
432
|
+
const [x, y] = point;
|
|
433
|
+
signedArea += (point[0] - previousPoint[0]) * (point[1] + previousPoint[1]);
|
|
434
|
+
previousPoint = point;
|
|
435
|
+
|
|
436
|
+
if (x < minX) minX = x;
|
|
437
|
+
if (y < minY) minY = y;
|
|
438
|
+
if (x > maxX) maxX = x;
|
|
439
|
+
if (y > maxY) maxY = y;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
return {
|
|
443
|
+
ring,
|
|
444
|
+
bbox: [minX, minY, maxX, maxY],
|
|
445
|
+
clockwise: signedArea >= 0,
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function contains(outerBbox: number[], innerBbox: number[]): boolean {
|
|
450
|
+
const [outerMinX, outerMinY, outerMaxX, outerMaxY] = outerBbox;
|
|
451
|
+
const [innerMinX, innerMinY, innerMaxX, innerMaxY] = innerBbox;
|
|
452
|
+
|
|
453
|
+
return (
|
|
454
|
+
outerMinX <= innerMinX &&
|
|
455
|
+
outerMinY <= innerMinY &&
|
|
456
|
+
outerMaxX >= innerMaxX &&
|
|
457
|
+
outerMaxY >= innerMaxY
|
|
458
|
+
);
|
|
459
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import JSZip from "jszip";
|
|
2
|
+
import proj4 from "proj4";
|
|
3
|
+
|
|
4
|
+
import { parseDbf } from "./parseDbf";
|
|
5
|
+
import { parseShp } from "./parseShp";
|
|
6
|
+
import { combine } from ".";
|
|
7
|
+
|
|
8
|
+
export async function parseZip(buffer: ArrayBuffer): Promise<GeoJSON.GeoJSON | GeoJSON.GeoJSON[]> {
|
|
9
|
+
const zip = await JSZip.loadAsync(buffer);
|
|
10
|
+
const names: string[] = [];
|
|
11
|
+
const projections: { [key: string]: proj4.Converter } = {};
|
|
12
|
+
|
|
13
|
+
for (const key of Object.keys(zip.files)) {
|
|
14
|
+
if (key.indexOf("__MACOSX") !== -1) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const fileExt = key.slice(-4).toLowerCase();
|
|
19
|
+
const fileName = key.slice(0, -4);
|
|
20
|
+
|
|
21
|
+
if (fileExt === ".shp") {
|
|
22
|
+
names.push(fileName);
|
|
23
|
+
zip.files[fileName + ".shp"] = zip.files[key];
|
|
24
|
+
} else if (fileExt === ".prj") {
|
|
25
|
+
projections[fileName] = proj4(await zip.files[key].async("text"));
|
|
26
|
+
} else if (key.slice(-5).toLowerCase() === ".json") {
|
|
27
|
+
names.push(fileName);
|
|
28
|
+
} else if (fileExt === ".dbf" || fileExt === ".cpg") {
|
|
29
|
+
zip.files[fileName + fileExt] = zip.files[key];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!names.length) {
|
|
34
|
+
throw new Error("no layers found");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const geojson = await Promise.all(
|
|
38
|
+
names.map(async name => {
|
|
39
|
+
const lastDotIdx = name.lastIndexOf(".");
|
|
40
|
+
if (lastDotIdx > -1 && name.slice(lastDotIdx).indexOf("json") > -1) {
|
|
41
|
+
const parsed = JSON.parse(await zip.files[name].async("text"));
|
|
42
|
+
parsed.name = name.slice(0, lastDotIdx);
|
|
43
|
+
return parsed;
|
|
44
|
+
} else {
|
|
45
|
+
const shpBuffer = await zip.files[name + ".shp"].async("arraybuffer");
|
|
46
|
+
const dbfBuffer = zip.files[name + ".dbf"]
|
|
47
|
+
? await zip.files[name + ".dbf"].async("arraybuffer")
|
|
48
|
+
: undefined;
|
|
49
|
+
const cpgString = zip.files[name + ".cpg"]
|
|
50
|
+
? await zip.files[name + ".cpg"].async("text")
|
|
51
|
+
: undefined;
|
|
52
|
+
const prj = projections[name];
|
|
53
|
+
|
|
54
|
+
const shp = parseShp(shpBuffer, prj);
|
|
55
|
+
const dbf = dbfBuffer ? parseDbf(dbfBuffer, cpgString) : undefined;
|
|
56
|
+
|
|
57
|
+
const parsed = combine(shp, dbf);
|
|
58
|
+
return parsed;
|
|
59
|
+
}
|
|
60
|
+
}),
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
return geojson.length === 1 ? geojson[0] : geojson;
|
|
64
|
+
}
|
|
@@ -6,14 +6,12 @@ import { JPLiteral } from "./expression";
|
|
|
6
6
|
|
|
7
7
|
export const VARIABLE_PREFIX = "czm_";
|
|
8
8
|
|
|
9
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
9
|
export function replaceVariables(expression: string, feature?: any): [string, JPLiteral[]] {
|
|
11
10
|
let exp = expression;
|
|
12
11
|
let result = "";
|
|
13
12
|
const literalJP: JPLiteral[] = [];
|
|
14
13
|
let i = exp.indexOf("${");
|
|
15
14
|
const featureDefined = typeof feature !== "undefined";
|
|
16
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
15
|
const jsonPathCache: Record<string, any[]> = {};
|
|
18
16
|
const varExpRegex = /^\$./;
|
|
19
17
|
while (i >= 0) {
|
|
@@ -68,7 +68,6 @@ export function evalLayerAppearances(
|
|
|
68
68
|
);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
72
71
|
function recursiveValEval(obj: any, layer: LayerSimple, feature?: Feature): any {
|
|
73
72
|
return Object.fromEntries(
|
|
74
73
|
Object.entries(obj).map(([k, v]) => {
|
|
@@ -92,7 +91,6 @@ export function clearAllExpressionCaches(
|
|
|
92
91
|
});
|
|
93
92
|
}
|
|
94
93
|
|
|
95
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
96
94
|
function recursiveClear(obj: any, layer: LayerSimple | undefined, feature: Feature | undefined) {
|
|
97
95
|
Object.entries(obj).forEach(([, v]) => {
|
|
98
96
|
// if v is an object itself and not a null, recurse deeper
|
|
@@ -115,18 +113,15 @@ function recursiveClear(obj: any, layer: LayerSimple | undefined, feature: Featu
|
|
|
115
113
|
});
|
|
116
114
|
}
|
|
117
115
|
|
|
118
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
119
116
|
function hasExpression(e: any): e is ExpressionContainer {
|
|
120
117
|
return typeof e === "object" && e && "expression" in e;
|
|
121
118
|
}
|
|
122
119
|
|
|
123
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
124
120
|
function hasNonExpressionObject(v: any): boolean {
|
|
125
121
|
return typeof v === "object" && v && !("expression" in v) && !Array.isArray(v);
|
|
126
122
|
}
|
|
127
123
|
|
|
128
124
|
export function evalExpression(
|
|
129
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
130
125
|
expressionContainer: any,
|
|
131
126
|
layer?: LayerSimple,
|
|
132
127
|
feature?: Feature,
|
|
@@ -7,7 +7,6 @@ export const generateRandomString = (len: number): string => {
|
|
|
7
7
|
.toLowerCase();
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
10
|
export const recursiveJSONParse = (obj: any): any => {
|
|
12
11
|
if (typeof obj !== "object" || obj === null) {
|
|
13
12
|
return obj;
|
package/src/test/utils.tsx
CHANGED
|
Binary file
|