@osmix/shapefile 0.0.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/CHANGELOG.md +14 -0
- package/README.md +64 -0
- package/dist/src/index.d.ts +33 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +33 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/osm-from-shapefile.d.ts +67 -0
- package/dist/src/osm-from-shapefile.d.ts.map +1 -0
- package/dist/src/osm-from-shapefile.js +335 -0
- package/dist/src/osm-from-shapefile.js.map +1 -0
- package/dist/src/types.d.ts +24 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +5 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils.d.ts +28 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +71 -0
- package/dist/src/utils.js.map +1 -0
- package/dist/test/osm-from-shapefile.test.d.ts +2 -0
- package/dist/test/osm-from-shapefile.test.d.ts.map +1 -0
- package/dist/test/osm-from-shapefile.test.js +460 -0
- package/dist/test/osm-from-shapefile.test.js.map +1 -0
- package/package.json +53 -0
- package/src/index.ts +33 -0
- package/src/osm-from-shapefile.ts +409 -0
- package/src/shpjs.d.ts +27 -0
- package/src/types.ts +24 -0
- package/src/utils.ts +82 -0
- package/test/osm-from-shapefile.test.ts +511 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
import { describe, expect, it, mock } from "bun:test"
|
|
2
|
+
import { Osm } from "@osmix/core"
|
|
3
|
+
import { progressEventMessage } from "@osmix/shared/progress"
|
|
4
|
+
import type { FeatureCollection, LineString, Point, Polygon } from "geojson"
|
|
5
|
+
import { startCreateOsmFromShapefile } from "../src/osm-from-shapefile"
|
|
6
|
+
|
|
7
|
+
// Mock shpjs module
|
|
8
|
+
mock.module("shpjs", () => ({
|
|
9
|
+
default: async (input: unknown) => {
|
|
10
|
+
// Return the mock data passed through
|
|
11
|
+
return input as FeatureCollection
|
|
12
|
+
},
|
|
13
|
+
}))
|
|
14
|
+
|
|
15
|
+
describe("@osmix/shapefile: startCreateOsmFromShapefile", () => {
|
|
16
|
+
it("should convert Point features to Nodes", () => {
|
|
17
|
+
const osm = new Osm()
|
|
18
|
+
const geojson: FeatureCollection<Point> = {
|
|
19
|
+
type: "FeatureCollection",
|
|
20
|
+
features: [
|
|
21
|
+
{
|
|
22
|
+
type: "Feature",
|
|
23
|
+
geometry: {
|
|
24
|
+
type: "Point",
|
|
25
|
+
coordinates: [-122.4194, 37.7749],
|
|
26
|
+
},
|
|
27
|
+
properties: {
|
|
28
|
+
name: "San Francisco",
|
|
29
|
+
population: 873965,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
type: "Feature",
|
|
34
|
+
geometry: {
|
|
35
|
+
type: "Point",
|
|
36
|
+
coordinates: [-122.4094, 37.7849],
|
|
37
|
+
},
|
|
38
|
+
properties: {
|
|
39
|
+
name: "Another Point",
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
for (const _ of startCreateOsmFromShapefile(osm, geojson, "test")) {
|
|
46
|
+
// Consume generator
|
|
47
|
+
}
|
|
48
|
+
osm.buildIndexes()
|
|
49
|
+
|
|
50
|
+
expect(osm.nodes.size).toBe(2)
|
|
51
|
+
expect(osm.ways.size).toBe(0)
|
|
52
|
+
|
|
53
|
+
const node1 = osm.nodes.getById(-1)
|
|
54
|
+
expect(node1).toBeDefined()
|
|
55
|
+
expect(node1?.lon).toBe(-122.4194)
|
|
56
|
+
expect(node1?.lat).toBe(37.7749)
|
|
57
|
+
expect(node1?.tags?.["name"]).toBe("San Francisco")
|
|
58
|
+
// OSM tags are stored as strings
|
|
59
|
+
expect(node1?.tags?.["population"]).toBe("873965")
|
|
60
|
+
|
|
61
|
+
const node2 = osm.nodes.getById(-2)
|
|
62
|
+
expect(node2).toBeDefined()
|
|
63
|
+
expect(node2?.lon).toBe(-122.4094)
|
|
64
|
+
expect(node2?.lat).toBe(37.7849)
|
|
65
|
+
expect(node2?.tags?.["name"]).toBe("Another Point")
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it("should convert LineString features to Ways with Nodes", () => {
|
|
69
|
+
const osm = new Osm()
|
|
70
|
+
const geojson: FeatureCollection<LineString> = {
|
|
71
|
+
type: "FeatureCollection",
|
|
72
|
+
features: [
|
|
73
|
+
{
|
|
74
|
+
type: "Feature",
|
|
75
|
+
geometry: {
|
|
76
|
+
type: "LineString",
|
|
77
|
+
coordinates: [
|
|
78
|
+
[-122.4194, 37.7749],
|
|
79
|
+
[-122.4094, 37.7849],
|
|
80
|
+
[-122.3994, 37.7949],
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
properties: {
|
|
84
|
+
highway: "primary",
|
|
85
|
+
name: "Main Street",
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
for (const _ of startCreateOsmFromShapefile(osm, geojson, "test")) {
|
|
92
|
+
// Consume generator
|
|
93
|
+
}
|
|
94
|
+
osm.buildIndexes()
|
|
95
|
+
|
|
96
|
+
expect(osm.nodes.size).toBe(3)
|
|
97
|
+
expect(osm.ways.size).toBe(1)
|
|
98
|
+
|
|
99
|
+
const way = osm.ways.getById(-1)
|
|
100
|
+
expect(way).toBeDefined()
|
|
101
|
+
expect(way?.refs).toHaveLength(3)
|
|
102
|
+
expect(way?.tags?.["highway"]).toBe("primary")
|
|
103
|
+
expect(way?.tags?.["name"]).toBe("Main Street")
|
|
104
|
+
|
|
105
|
+
// Verify nodes were created
|
|
106
|
+
const node1 = osm.nodes.getById(way!.refs[0]!)
|
|
107
|
+
const node2 = osm.nodes.getById(way!.refs[1]!)
|
|
108
|
+
const node3 = osm.nodes.getById(way!.refs[2]!)
|
|
109
|
+
|
|
110
|
+
expect(node1?.lon).toBe(-122.4194)
|
|
111
|
+
expect(node1?.lat).toBe(37.7749)
|
|
112
|
+
expect(node2?.lon).toBe(-122.4094)
|
|
113
|
+
expect(node2?.lat).toBe(37.7849)
|
|
114
|
+
expect(node3?.lon).toBe(-122.3994)
|
|
115
|
+
expect(node3?.lat).toBe(37.7949)
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
it("should convert simple Polygon features to Ways with area tags", () => {
|
|
119
|
+
const osm = new Osm()
|
|
120
|
+
const geojson: FeatureCollection<Polygon> = {
|
|
121
|
+
type: "FeatureCollection",
|
|
122
|
+
features: [
|
|
123
|
+
{
|
|
124
|
+
type: "Feature",
|
|
125
|
+
geometry: {
|
|
126
|
+
type: "Polygon",
|
|
127
|
+
coordinates: [
|
|
128
|
+
[
|
|
129
|
+
[-122.4194, 37.7749],
|
|
130
|
+
[-122.4094, 37.7749],
|
|
131
|
+
[-122.4094, 37.7849],
|
|
132
|
+
[-122.4194, 37.7849],
|
|
133
|
+
[-122.4194, 37.7749], // Closed ring
|
|
134
|
+
],
|
|
135
|
+
],
|
|
136
|
+
},
|
|
137
|
+
properties: {
|
|
138
|
+
building: "yes",
|
|
139
|
+
name: "Test Building",
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
for (const _ of startCreateOsmFromShapefile(osm, geojson, "test")) {
|
|
146
|
+
// Consume generator
|
|
147
|
+
}
|
|
148
|
+
osm.buildIndexes()
|
|
149
|
+
|
|
150
|
+
expect(osm.ways.size).toBe(1)
|
|
151
|
+
expect(osm.relations.size).toBe(0) // No relation for simple polygon
|
|
152
|
+
|
|
153
|
+
const way = osm.ways.getById(-1)
|
|
154
|
+
expect(way).toBeDefined()
|
|
155
|
+
expect(way?.tags?.["building"]).toBe("yes")
|
|
156
|
+
expect(way?.tags?.["name"]).toBe("Test Building")
|
|
157
|
+
expect(way?.tags?.["area"]).toBe("yes")
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
it("should convert Polygon with holes to relation with multiple Ways", () => {
|
|
161
|
+
const osm = new Osm()
|
|
162
|
+
const geojson: FeatureCollection<Polygon> = {
|
|
163
|
+
type: "FeatureCollection",
|
|
164
|
+
features: [
|
|
165
|
+
{
|
|
166
|
+
type: "Feature",
|
|
167
|
+
geometry: {
|
|
168
|
+
type: "Polygon",
|
|
169
|
+
coordinates: [
|
|
170
|
+
// Outer ring
|
|
171
|
+
[
|
|
172
|
+
[-122.4194, 37.7749],
|
|
173
|
+
[-122.4094, 37.7749],
|
|
174
|
+
[-122.4094, 37.7849],
|
|
175
|
+
[-122.4194, 37.7849],
|
|
176
|
+
[-122.4194, 37.7749],
|
|
177
|
+
],
|
|
178
|
+
// Hole
|
|
179
|
+
[
|
|
180
|
+
[-122.4164, 37.7779],
|
|
181
|
+
[-122.4144, 37.7779],
|
|
182
|
+
[-122.4144, 37.7799],
|
|
183
|
+
[-122.4164, 37.7799],
|
|
184
|
+
[-122.4164, 37.7779],
|
|
185
|
+
],
|
|
186
|
+
],
|
|
187
|
+
},
|
|
188
|
+
properties: {
|
|
189
|
+
building: "yes",
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
for (const _ of startCreateOsmFromShapefile(osm, geojson, "test")) {
|
|
196
|
+
// Consume generator
|
|
197
|
+
}
|
|
198
|
+
osm.buildIndexes()
|
|
199
|
+
|
|
200
|
+
// Should have outer ring way + hole way + relation
|
|
201
|
+
expect(osm.ways.size).toBe(2)
|
|
202
|
+
expect(osm.relations.size).toBe(1)
|
|
203
|
+
|
|
204
|
+
const relation = osm.relations.getById(-1)
|
|
205
|
+
expect(relation).toBeDefined()
|
|
206
|
+
expect(relation?.tags?.["type"]).toBe("multipolygon")
|
|
207
|
+
expect(relation?.tags?.["building"]).toBe("yes")
|
|
208
|
+
expect(relation?.members).toHaveLength(2)
|
|
209
|
+
expect(relation?.members[0]?.role).toBe("outer")
|
|
210
|
+
expect(relation?.members[1]?.role).toBe("inner")
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
it("should convert MultiPoint features to multiple Nodes", () => {
|
|
214
|
+
const osm = new Osm()
|
|
215
|
+
const geojson: FeatureCollection = {
|
|
216
|
+
type: "FeatureCollection",
|
|
217
|
+
features: [
|
|
218
|
+
{
|
|
219
|
+
type: "Feature",
|
|
220
|
+
geometry: {
|
|
221
|
+
type: "MultiPoint",
|
|
222
|
+
coordinates: [
|
|
223
|
+
[-122.4194, 37.7749],
|
|
224
|
+
[-122.4094, 37.7849],
|
|
225
|
+
[-122.3994, 37.7949],
|
|
226
|
+
],
|
|
227
|
+
},
|
|
228
|
+
properties: {
|
|
229
|
+
type: "stop",
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
],
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
for (const _ of startCreateOsmFromShapefile(osm, geojson, "test")) {
|
|
236
|
+
// Consume generator
|
|
237
|
+
}
|
|
238
|
+
osm.buildIndexes()
|
|
239
|
+
|
|
240
|
+
expect(osm.nodes.size).toBe(3)
|
|
241
|
+
expect(osm.ways.size).toBe(0)
|
|
242
|
+
|
|
243
|
+
// All three nodes should have the same tags
|
|
244
|
+
const node1 = osm.nodes.getById(-1)
|
|
245
|
+
const node2 = osm.nodes.getById(-2)
|
|
246
|
+
const node3 = osm.nodes.getById(-3)
|
|
247
|
+
|
|
248
|
+
expect(node1?.tags?.["type"]).toBe("stop")
|
|
249
|
+
expect(node2?.tags?.["type"]).toBe("stop")
|
|
250
|
+
expect(node3?.tags?.["type"]).toBe("stop")
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
it("should handle features without properties", () => {
|
|
254
|
+
const osm = new Osm()
|
|
255
|
+
const geojson: FeatureCollection<Point> = {
|
|
256
|
+
type: "FeatureCollection",
|
|
257
|
+
features: [
|
|
258
|
+
{
|
|
259
|
+
type: "Feature",
|
|
260
|
+
geometry: {
|
|
261
|
+
type: "Point",
|
|
262
|
+
coordinates: [-122.4194, 37.7749],
|
|
263
|
+
},
|
|
264
|
+
properties: null,
|
|
265
|
+
},
|
|
266
|
+
],
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
for (const _ of startCreateOsmFromShapefile(osm, geojson, "test")) {
|
|
270
|
+
// Consume generator
|
|
271
|
+
}
|
|
272
|
+
osm.buildIndexes()
|
|
273
|
+
|
|
274
|
+
expect(osm.nodes.size).toBe(1)
|
|
275
|
+
const node = osm.nodes.getById(-1)
|
|
276
|
+
expect(node).toBeDefined()
|
|
277
|
+
expect(node?.tags).toBeUndefined()
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
it("should reuse nodes when features share coordinates", () => {
|
|
281
|
+
const osm = new Osm()
|
|
282
|
+
const geojson: FeatureCollection<LineString> = {
|
|
283
|
+
type: "FeatureCollection",
|
|
284
|
+
features: [
|
|
285
|
+
{
|
|
286
|
+
type: "Feature",
|
|
287
|
+
geometry: {
|
|
288
|
+
type: "LineString",
|
|
289
|
+
coordinates: [
|
|
290
|
+
[-122.4194, 37.7749],
|
|
291
|
+
[-122.4094, 37.7849],
|
|
292
|
+
],
|
|
293
|
+
},
|
|
294
|
+
properties: {
|
|
295
|
+
highway: "primary",
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
type: "Feature",
|
|
300
|
+
geometry: {
|
|
301
|
+
type: "LineString",
|
|
302
|
+
coordinates: [
|
|
303
|
+
[-122.4094, 37.7849], // Shared coordinate
|
|
304
|
+
[-122.3994, 37.7949],
|
|
305
|
+
],
|
|
306
|
+
},
|
|
307
|
+
properties: {
|
|
308
|
+
highway: "secondary",
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
],
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
for (const _ of startCreateOsmFromShapefile(osm, geojson, "test")) {
|
|
315
|
+
// Consume generator
|
|
316
|
+
}
|
|
317
|
+
osm.buildIndexes()
|
|
318
|
+
|
|
319
|
+
// Should have 3 nodes (shared coordinate is reused)
|
|
320
|
+
expect(osm.nodes.size).toBe(3)
|
|
321
|
+
expect(osm.ways.size).toBe(2)
|
|
322
|
+
|
|
323
|
+
const way1 = osm.ways.getById(-1)
|
|
324
|
+
const way2 = osm.ways.getById(-2)
|
|
325
|
+
|
|
326
|
+
// Each way should have 2 nodes
|
|
327
|
+
expect(way1?.refs).toHaveLength(2)
|
|
328
|
+
expect(way2?.refs).toHaveLength(2)
|
|
329
|
+
// Nodes at the same coordinate are reused
|
|
330
|
+
expect(way1?.refs[1]).toBe(way2?.refs[0])
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
it("should use generator for custom progress handling", () => {
|
|
334
|
+
const osm = new Osm()
|
|
335
|
+
const geojson: FeatureCollection<Point> = {
|
|
336
|
+
type: "FeatureCollection",
|
|
337
|
+
features: [
|
|
338
|
+
{
|
|
339
|
+
type: "Feature",
|
|
340
|
+
geometry: {
|
|
341
|
+
type: "Point",
|
|
342
|
+
coordinates: [-122.4194, 37.7749],
|
|
343
|
+
},
|
|
344
|
+
properties: {},
|
|
345
|
+
},
|
|
346
|
+
],
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const progressMessages: string[] = []
|
|
350
|
+
for (const update of startCreateOsmFromShapefile(osm, geojson, "test")) {
|
|
351
|
+
progressMessages.push(progressEventMessage(update))
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
expect(progressMessages.length).toBeGreaterThan(0)
|
|
355
|
+
expect(progressMessages[0]).toContain("Converting")
|
|
356
|
+
expect(progressMessages[progressMessages.length - 1]).toContain(
|
|
357
|
+
"Finished converting",
|
|
358
|
+
)
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
it("should use feature IDs when present", () => {
|
|
362
|
+
const osm = new Osm()
|
|
363
|
+
const geojson: FeatureCollection<Point | LineString> = {
|
|
364
|
+
type: "FeatureCollection",
|
|
365
|
+
features: [
|
|
366
|
+
{
|
|
367
|
+
type: "Feature",
|
|
368
|
+
id: 100,
|
|
369
|
+
geometry: {
|
|
370
|
+
type: "Point",
|
|
371
|
+
coordinates: [-122.4194, 37.7749],
|
|
372
|
+
},
|
|
373
|
+
properties: {
|
|
374
|
+
name: "Point with ID",
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
type: "Feature",
|
|
379
|
+
id: "200",
|
|
380
|
+
geometry: {
|
|
381
|
+
type: "LineString",
|
|
382
|
+
coordinates: [
|
|
383
|
+
[-122.4194, 37.7749],
|
|
384
|
+
[-122.4094, 37.7849],
|
|
385
|
+
],
|
|
386
|
+
},
|
|
387
|
+
properties: {
|
|
388
|
+
highway: "primary",
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
],
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
for (const _ of startCreateOsmFromShapefile(osm, geojson, "test")) {
|
|
395
|
+
// Consume generator
|
|
396
|
+
}
|
|
397
|
+
osm.buildIndexes()
|
|
398
|
+
|
|
399
|
+
// Point should use ID 100
|
|
400
|
+
const node = osm.nodes.getById(100)
|
|
401
|
+
expect(node).toBeDefined()
|
|
402
|
+
expect(node?.tags?.["name"]).toBe("Point with ID")
|
|
403
|
+
|
|
404
|
+
// Way should use ID 200
|
|
405
|
+
const way = osm.ways.getById(200)
|
|
406
|
+
expect(way).toBeDefined()
|
|
407
|
+
expect(way?.tags?.["highway"]).toBe("primary")
|
|
408
|
+
})
|
|
409
|
+
|
|
410
|
+
it("should handle MultiLineString features", () => {
|
|
411
|
+
const osm = new Osm()
|
|
412
|
+
const geojson: FeatureCollection = {
|
|
413
|
+
type: "FeatureCollection",
|
|
414
|
+
features: [
|
|
415
|
+
{
|
|
416
|
+
type: "Feature",
|
|
417
|
+
geometry: {
|
|
418
|
+
type: "MultiLineString",
|
|
419
|
+
coordinates: [
|
|
420
|
+
[
|
|
421
|
+
[-122.4194, 37.7749],
|
|
422
|
+
[-122.4094, 37.7849],
|
|
423
|
+
],
|
|
424
|
+
[
|
|
425
|
+
[-122.3994, 37.7949],
|
|
426
|
+
[-122.3894, 37.8049],
|
|
427
|
+
],
|
|
428
|
+
],
|
|
429
|
+
},
|
|
430
|
+
properties: {
|
|
431
|
+
highway: "secondary",
|
|
432
|
+
},
|
|
433
|
+
},
|
|
434
|
+
],
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
for (const _ of startCreateOsmFromShapefile(osm, geojson, "test")) {
|
|
438
|
+
// Consume generator
|
|
439
|
+
}
|
|
440
|
+
osm.buildIndexes()
|
|
441
|
+
|
|
442
|
+
// Should create 2 ways (one for each line)
|
|
443
|
+
expect(osm.ways.size).toBe(2)
|
|
444
|
+
expect(osm.nodes.size).toBe(4)
|
|
445
|
+
|
|
446
|
+
const way1 = osm.ways.getById(-1)
|
|
447
|
+
const way2 = osm.ways.getById(-2)
|
|
448
|
+
|
|
449
|
+
expect(way1?.refs).toHaveLength(2)
|
|
450
|
+
expect(way2?.refs).toHaveLength(2)
|
|
451
|
+
expect(way1?.tags?.["highway"]).toBe("secondary")
|
|
452
|
+
expect(way2?.tags?.["highway"]).toBe("secondary")
|
|
453
|
+
})
|
|
454
|
+
|
|
455
|
+
it("should handle MultiPolygon features", () => {
|
|
456
|
+
const osm = new Osm()
|
|
457
|
+
const geojson: FeatureCollection = {
|
|
458
|
+
type: "FeatureCollection",
|
|
459
|
+
features: [
|
|
460
|
+
{
|
|
461
|
+
type: "Feature",
|
|
462
|
+
geometry: {
|
|
463
|
+
type: "MultiPolygon",
|
|
464
|
+
coordinates: [
|
|
465
|
+
// First polygon
|
|
466
|
+
[
|
|
467
|
+
[
|
|
468
|
+
[-122.4194, 37.7749],
|
|
469
|
+
[-122.4094, 37.7749],
|
|
470
|
+
[-122.4094, 37.7849],
|
|
471
|
+
[-122.4194, 37.7849],
|
|
472
|
+
[-122.4194, 37.7749],
|
|
473
|
+
],
|
|
474
|
+
],
|
|
475
|
+
// Second polygon
|
|
476
|
+
[
|
|
477
|
+
[
|
|
478
|
+
[-122.3994, 37.7649],
|
|
479
|
+
[-122.3894, 37.7649],
|
|
480
|
+
[-122.3894, 37.7749],
|
|
481
|
+
[-122.3994, 37.7749],
|
|
482
|
+
[-122.3994, 37.7649],
|
|
483
|
+
],
|
|
484
|
+
],
|
|
485
|
+
],
|
|
486
|
+
},
|
|
487
|
+
properties: {
|
|
488
|
+
landuse: "residential",
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
],
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
for (const _ of startCreateOsmFromShapefile(osm, geojson, "test")) {
|
|
495
|
+
// Consume generator
|
|
496
|
+
}
|
|
497
|
+
osm.buildIndexes()
|
|
498
|
+
|
|
499
|
+
// Should have 2 ways + 1 relation
|
|
500
|
+
expect(osm.ways.size).toBe(2)
|
|
501
|
+
expect(osm.relations.size).toBe(1)
|
|
502
|
+
|
|
503
|
+
const relation = osm.relations.getById(-1)
|
|
504
|
+
expect(relation).toBeDefined()
|
|
505
|
+
expect(relation?.tags?.["type"]).toBe("multipolygon")
|
|
506
|
+
expect(relation?.tags?.["landuse"]).toBe("residential")
|
|
507
|
+
expect(relation?.members).toHaveLength(2)
|
|
508
|
+
expect(relation?.members[0]?.role).toBe("outer")
|
|
509
|
+
expect(relation?.members[1]?.role).toBe("outer")
|
|
510
|
+
})
|
|
511
|
+
})
|