@osmix/core 0.0.2 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +118 -107
  3. package/dist/core/src/entities.d.ts +114 -0
  4. package/dist/core/src/entities.d.ts.map +1 -0
  5. package/dist/core/src/entities.js +152 -0
  6. package/dist/core/src/entities.js.map +1 -0
  7. package/dist/core/src/ids.d.ts +113 -0
  8. package/dist/core/src/ids.d.ts.map +1 -0
  9. package/dist/{src → core/src}/ids.js +96 -31
  10. package/dist/core/src/ids.js.map +1 -0
  11. package/dist/core/src/index.d.ts +32 -0
  12. package/dist/core/src/index.d.ts.map +1 -0
  13. package/dist/core/src/index.js +35 -0
  14. package/dist/core/src/index.js.map +1 -0
  15. package/dist/core/src/nodes.d.ts +101 -0
  16. package/dist/core/src/nodes.d.ts.map +1 -0
  17. package/dist/core/src/nodes.js +309 -0
  18. package/dist/core/src/nodes.js.map +1 -0
  19. package/dist/core/src/osm.d.ts +74 -0
  20. package/dist/core/src/osm.d.ts.map +1 -0
  21. package/dist/core/src/osm.js +120 -0
  22. package/dist/core/src/osm.js.map +1 -0
  23. package/dist/core/src/relations.d.ts +118 -0
  24. package/dist/core/src/relations.d.ts.map +1 -0
  25. package/dist/core/src/relations.js +412 -0
  26. package/dist/core/src/relations.js.map +1 -0
  27. package/dist/core/src/stringtable.d.ts +95 -0
  28. package/dist/core/src/stringtable.d.ts.map +1 -0
  29. package/dist/core/src/stringtable.js +170 -0
  30. package/dist/core/src/stringtable.js.map +1 -0
  31. package/dist/core/src/tags.d.ts +126 -0
  32. package/dist/core/src/tags.d.ts.map +1 -0
  33. package/dist/core/src/tags.js +228 -0
  34. package/dist/core/src/tags.js.map +1 -0
  35. package/dist/core/src/typed-arrays.d.ts +124 -0
  36. package/dist/core/src/typed-arrays.d.ts.map +1 -0
  37. package/dist/{src → core/src}/typed-arrays.js +88 -9
  38. package/dist/core/src/typed-arrays.js.map +1 -0
  39. package/dist/core/src/utils.d.ts +11 -0
  40. package/dist/core/src/utils.d.ts.map +1 -0
  41. package/dist/{src → core/src}/utils.js +8 -10
  42. package/dist/core/src/utils.js.map +1 -0
  43. package/dist/core/src/ways.d.ts +101 -0
  44. package/dist/core/src/ways.d.ts.map +1 -0
  45. package/dist/core/src/ways.js +336 -0
  46. package/dist/core/src/ways.js.map +1 -0
  47. package/dist/core/test/memory.test.d.ts +7 -0
  48. package/dist/core/test/memory.test.d.ts.map +1 -0
  49. package/dist/core/test/memory.test.js +29 -0
  50. package/dist/core/test/memory.test.js.map +1 -0
  51. package/dist/{test → core/test}/mock-osm.d.ts +3 -3
  52. package/dist/core/test/mock-osm.d.ts.map +1 -0
  53. package/dist/{test → core/test}/mock-osm.js +3 -3
  54. package/dist/core/test/mock-osm.js.map +1 -0
  55. package/dist/core/test/tags-search.test.d.ts +2 -0
  56. package/dist/core/test/tags-search.test.d.ts.map +1 -0
  57. package/dist/core/test/tags-search.test.js +56 -0
  58. package/dist/core/test/tags-search.test.js.map +1 -0
  59. package/dist/core/test/typed-arrays.test.d.ts.map +1 -0
  60. package/dist/{test → core/test}/typed-arrays.test.js +19 -17
  61. package/dist/core/test/typed-arrays.test.js.map +1 -0
  62. package/dist/osmix/src/extract.d.ts +43 -0
  63. package/dist/osmix/src/extract.d.ts.map +1 -0
  64. package/dist/osmix/src/extract.js +156 -0
  65. package/dist/osmix/src/extract.js.map +1 -0
  66. package/dist/osmix/src/pbf.d.ts +55 -0
  67. package/dist/osmix/src/pbf.d.ts.map +1 -0
  68. package/dist/osmix/src/pbf.js +187 -0
  69. package/dist/osmix/src/pbf.js.map +1 -0
  70. package/dist/osmix/src/utils.d.ts +36 -0
  71. package/dist/osmix/src/utils.d.ts.map +1 -0
  72. package/dist/osmix/src/utils.js +108 -0
  73. package/dist/osmix/src/utils.js.map +1 -0
  74. package/dist/osmix/test/extract.bench.d.ts.map +1 -0
  75. package/dist/{test → osmix/test}/extract.bench.js +8 -5
  76. package/dist/osmix/test/extract.bench.js.map +1 -0
  77. package/dist/osmix/test/extract.test.d.ts.map +1 -0
  78. package/dist/osmix/test/extract.test.js +392 -0
  79. package/dist/osmix/test/extract.test.js.map +1 -0
  80. package/package.json +10 -12
  81. package/src/entities.ts +138 -22
  82. package/src/ids.ts +117 -45
  83. package/src/index.ts +34 -5
  84. package/src/nodes.ts +237 -58
  85. package/src/osm.ts +174 -0
  86. package/src/relations.ts +383 -54
  87. package/src/stringtable.ts +111 -36
  88. package/src/tags.ts +207 -46
  89. package/src/typed-arrays.ts +97 -10
  90. package/src/types/geoflatbush.d.ts +37 -0
  91. package/src/types/geokdbush.d.ts +37 -0
  92. package/src/types/kdbush.d.ts +24 -6
  93. package/src/utils.ts +9 -14
  94. package/src/ways.ts +248 -84
  95. package/test/memory.test.ts +38 -0
  96. package/test/mock-osm.ts +8 -8
  97. package/test/tags-search.test.ts +60 -0
  98. package/test/typed-arrays.test.ts +5 -6
  99. package/tsconfig.json +7 -1
  100. package/dist/src/entities.d.ts +0 -26
  101. package/dist/src/entities.d.ts.map +0 -1
  102. package/dist/src/entities.js +0 -69
  103. package/dist/src/entities.js.map +0 -1
  104. package/dist/src/ids.d.ts +0 -50
  105. package/dist/src/ids.d.ts.map +0 -1
  106. package/dist/src/ids.js.map +0 -1
  107. package/dist/src/index.d.ts +0 -6
  108. package/dist/src/index.d.ts.map +0 -1
  109. package/dist/src/index.js +0 -7
  110. package/dist/src/index.js.map +0 -1
  111. package/dist/src/nodes.d.ts +0 -36
  112. package/dist/src/nodes.d.ts.map +0 -1
  113. package/dist/src/nodes.js +0 -171
  114. package/dist/src/nodes.js.map +0 -1
  115. package/dist/src/osmix.d.ts +0 -88
  116. package/dist/src/osmix.d.ts.map +0 -1
  117. package/dist/src/osmix.js +0 -438
  118. package/dist/src/osmix.js.map +0 -1
  119. package/dist/src/relations.d.ts +0 -31
  120. package/dist/src/relations.d.ts.map +0 -1
  121. package/dist/src/relations.js +0 -161
  122. package/dist/src/relations.js.map +0 -1
  123. package/dist/src/stringtable.d.ts +0 -37
  124. package/dist/src/stringtable.d.ts.map +0 -1
  125. package/dist/src/stringtable.js +0 -101
  126. package/dist/src/stringtable.js.map +0 -1
  127. package/dist/src/tags.d.ts +0 -33
  128. package/dist/src/tags.d.ts.map +0 -1
  129. package/dist/src/tags.js +0 -92
  130. package/dist/src/tags.js.map +0 -1
  131. package/dist/src/typed-arrays.d.ts +0 -50
  132. package/dist/src/typed-arrays.d.ts.map +0 -1
  133. package/dist/src/typed-arrays.js.map +0 -1
  134. package/dist/src/utils.d.ts +0 -4
  135. package/dist/src/utils.d.ts.map +0 -1
  136. package/dist/src/utils.js.map +0 -1
  137. package/dist/src/ways.d.ts +0 -42
  138. package/dist/src/ways.d.ts.map +0 -1
  139. package/dist/src/ways.js +0 -186
  140. package/dist/src/ways.js.map +0 -1
  141. package/dist/test/extract.bench.d.ts.map +0 -1
  142. package/dist/test/extract.bench.js.map +0 -1
  143. package/dist/test/extract.test.d.ts.map +0 -1
  144. package/dist/test/extract.test.js +0 -127
  145. package/dist/test/extract.test.js.map +0 -1
  146. package/dist/test/mock-osm.d.ts.map +0 -1
  147. package/dist/test/mock-osm.js.map +0 -1
  148. package/dist/test/read.test.d.ts +0 -2
  149. package/dist/test/read.test.d.ts.map +0 -1
  150. package/dist/test/read.test.js +0 -17
  151. package/dist/test/read.test.js.map +0 -1
  152. package/dist/test/typed-arrays.test.d.ts.map +0 -1
  153. package/dist/test/typed-arrays.test.js.map +0 -1
  154. package/dist/test/write.test.d.ts +0 -2
  155. package/dist/test/write.test.d.ts.map +0 -1
  156. package/dist/test/write.test.js +0 -55
  157. package/dist/test/write.test.js.map +0 -1
  158. package/src/osmix.ts +0 -556
  159. package/test/extract.bench.ts +0 -29
  160. package/test/extract.test.ts +0 -161
  161. package/test/read.test.ts +0 -22
  162. package/test/write.test.ts +0 -69
  163. /package/dist/{test → core/test}/typed-arrays.test.d.ts +0 -0
  164. /package/dist/{test → osmix/test}/extract.bench.d.ts +0 -0
  165. /package/dist/{test → osmix/test}/extract.test.d.ts +0 -0
package/src/osmix.ts DELETED
@@ -1,556 +0,0 @@
1
- import {
2
- isNode,
3
- isRelation,
4
- isWay,
5
- nodeToFeature,
6
- type OsmEntity,
7
- type OsmEntityType,
8
- type OsmEntityTypeMap,
9
- type OsmixGeoJSONFeature,
10
- OsmJsonToBlocksTransformStream,
11
- type OsmNode,
12
- type OsmRelation,
13
- type OsmWay,
14
- relationToFeature,
15
- wayToFeature,
16
- } from "@osmix/json"
17
- import {
18
- type AsyncGeneratorValue,
19
- OsmBlocksToPbfBytesTransformStream,
20
- type OsmPbfBlock,
21
- type OsmPbfHeaderBlock,
22
- readOsmPbf,
23
- } from "@osmix/pbf"
24
- import type { GeoBbox2D, LonLat } from "@osmix/shared/types"
25
- import { Nodes, type NodesTransferables } from "./nodes"
26
- import { Relations, type RelationsTransferables } from "./relations"
27
- import StringTable, { type StringTableTransferables } from "./stringtable"
28
- import { IdArrayType } from "./typed-arrays"
29
- import { bboxFromLonLats, throttle } from "./utils"
30
- import { Ways, type WaysTransferables } from "./ways"
31
-
32
- export interface OsmixTransferables {
33
- id: string
34
- header: OsmPbfHeaderBlock
35
- stringTable: StringTableTransferables
36
- nodes: NodesTransferables
37
- ways: WaysTransferables
38
- relations: RelationsTransferables
39
- parsingTimeMs: number
40
- }
41
-
42
- export interface OsmixOptions {
43
- id: string
44
- extractBbox: GeoBbox2D
45
- logger: (message: string, type?: LogLevel) => void
46
- filter<T extends OsmEntityType>(
47
- type: T,
48
- entity: OsmEntityTypeMap[T],
49
- osmix: Osmix,
50
- ): boolean
51
- header: OsmPbfHeaderBlock
52
- buildSpatialIndexes: OsmEntityType[]
53
-
54
- // Future options
55
- // include: OsmEntityType[]
56
- }
57
-
58
- export type LogLevel = "debug" | "info" | "warn" | "error"
59
-
60
- /**
61
- * OSM Entity Index.
62
- */
63
- export class Osmix {
64
- // Filename or ID of this OSM Entity index.
65
- id = "unknown"
66
- header: OsmPbfHeaderBlock = {
67
- required_features: [],
68
- optional_features: [],
69
- }
70
- blocksGenerator: AsyncGenerator<OsmPbfBlock> | null = null
71
-
72
- // Shared string lookup table for all nodes, ways, and relations
73
- stringTable: StringTable
74
- nodes: Nodes
75
- ways: Ways
76
- relations: Relations
77
-
78
- log = (message: string, type?: LogLevel) =>
79
- type === "error" ? console.error(message) : console.log(message)
80
-
81
- #indexBuilt = false
82
- #startTime = performance.now()
83
- buildTimeMs = 0
84
-
85
- static from({
86
- id,
87
- header,
88
- stringTable,
89
- nodes,
90
- ways,
91
- relations,
92
- parsingTimeMs,
93
- }: OsmixTransferables) {
94
- const osm = new Osmix({ id, header })
95
- osm.stringTable = StringTable.from(stringTable)
96
- osm.nodes = Nodes.from(osm.stringTable, nodes)
97
- osm.ways = Ways.from(osm.stringTable, ways)
98
- osm.relations = Relations.from(osm.stringTable, relations)
99
- osm.buildTimeMs = parsingTimeMs
100
- osm.#indexBuilt = true
101
- return osm
102
- }
103
-
104
- /**
105
- * Easiest way to get started with Osmix. Reads a PBF file into an Osmix index. Logs progress to the console.
106
- */
107
- static async fromPbf(
108
- data: AsyncGeneratorValue<Uint8Array<ArrayBufferLike>>,
109
- options: Partial<OsmixOptions> = {},
110
- ) {
111
- const osm = new Osmix(options)
112
- await osm.readPbf(data, options)
113
-
114
- // By default, build all spatial indexes.
115
- if (!Array.isArray(options.buildSpatialIndexes)) {
116
- osm.buildSpatialIndexes()
117
- } else if (options.buildSpatialIndexes.includes("node")) {
118
- osm.nodes.buildSpatialIndex()
119
- } else if (options.buildSpatialIndexes.includes("way")) {
120
- osm.ways.buildSpatialIndex(osm.nodes)
121
- }
122
-
123
- return osm
124
- }
125
-
126
- constructor(options: Partial<OsmixOptions> = {}) {
127
- if (options.header) this.header = options.header
128
- if (options.id) this.id = options.id
129
- if (options.logger) this.log = options.logger
130
- this.stringTable = new StringTable()
131
- this.nodes = new Nodes(this.stringTable)
132
- this.ways = new Ways(this.stringTable)
133
- this.relations = new Relations(this.stringTable)
134
- }
135
-
136
- setLogger(listener: (message: string, type?: LogLevel) => void) {
137
- this.log = listener
138
- }
139
-
140
- createThrottledLog(interval: number) {
141
- return throttle(this.log, interval)
142
- }
143
-
144
- buildIndexes() {
145
- if (!this.nodes.isReady) this.nodes.buildIndex()
146
- if (!this.ways.isReady) this.ways.buildIndex()
147
- if (!this.relations.isReady) this.relations.buildIndex()
148
- this.stringTable.buildIndex()
149
- this.#indexBuilt = true
150
- this.buildTimeMs = performance.now() - this.#startTime
151
- }
152
-
153
- isReady() {
154
- return this.#indexBuilt
155
- }
156
-
157
- transferables(): OsmixTransferables {
158
- return {
159
- id: this.id,
160
- header: this.header,
161
- stringTable: this.stringTable.transferables(),
162
- nodes: this.nodes.transferables(),
163
- ways: this.ways.transferables(),
164
- relations: this.relations.transferables(),
165
- parsingTimeMs: this.buildTimeMs,
166
- }
167
- }
168
-
169
- async readPbf(
170
- data: AsyncGeneratorValue<Uint8Array<ArrayBufferLike>>,
171
- options: Partial<OsmixOptions> = {},
172
- ) {
173
- if (this.#indexBuilt) throw Error("Osmix built. Create new instance.")
174
- const { extractBbox } = options
175
- const { header, blocks } = await readOsmPbf(data)
176
- this.header = header
177
- if (extractBbox) {
178
- this.header.bbox = {
179
- left: extractBbox[0],
180
- bottom: extractBbox[1],
181
- right: extractBbox[2],
182
- top: extractBbox[3],
183
- }
184
- }
185
- const logEverySecond = this.createThrottledLog(1_000)
186
-
187
- for await (const block of blocks) {
188
- const blockStringIndexMap = this.stringTable.createBlockIndexMap(block)
189
-
190
- for (const group of block.primitivegroup) {
191
- const { nodes, ways, relations, dense } = group
192
- if (nodes && nodes.length > 0) {
193
- throw Error("Nodes must be dense!")
194
- }
195
-
196
- if (dense) {
197
- this.nodes.addDenseNodes(
198
- dense,
199
- block,
200
- blockStringIndexMap,
201
- extractBbox
202
- ? (node: OsmNode) => {
203
- return (
204
- node.lon >= extractBbox[0] &&
205
- node.lon <= extractBbox[2] &&
206
- node.lat >= extractBbox[1] &&
207
- node.lat <= extractBbox[3]
208
- )
209
- }
210
- : undefined,
211
- )
212
-
213
- logEverySecond(`${this.nodes.size.toLocaleString()} nodes added`)
214
- }
215
-
216
- if (ways.length > 0) {
217
- // Nodes are finished, build their index.
218
- if (!this.nodes.isReady) this.nodes.buildIndex()
219
- this.ways.addWays(
220
- ways,
221
- blockStringIndexMap,
222
- extractBbox
223
- ? (way: OsmWay) => {
224
- const refs = way.refs.filter((ref) => this.nodes.ids.has(ref))
225
- if (refs.length === 0) return null
226
- return {
227
- ...way,
228
- refs,
229
- }
230
- }
231
- : undefined,
232
- )
233
-
234
- logEverySecond(`${this.ways.size.toLocaleString()} ways added`)
235
- }
236
-
237
- if (relations.length > 0) {
238
- if (!this.ways.isReady) this.ways.buildIndex()
239
- this.relations.addRelations(
240
- relations,
241
- blockStringIndexMap,
242
- extractBbox
243
- ? (relation: OsmRelation) => {
244
- const members = relation.members.filter((member) => {
245
- if (member.type === "node")
246
- return this.nodes.ids.has(member.ref)
247
- if (member.type === "way")
248
- return this.ways.ids.has(member.ref)
249
- return false
250
- })
251
- if (members.length === 0) return null
252
- return {
253
- ...relation,
254
- members,
255
- }
256
- }
257
- : undefined,
258
- )
259
-
260
- logEverySecond(
261
- `${this.relations.size.toLocaleString()} relations added`,
262
- )
263
- }
264
- }
265
- }
266
-
267
- this.log(
268
- `${this.nodes.size.toLocaleString()} nodes, ${this.ways.size.toLocaleString()} ways, and ${this.relations.size.toLocaleString()} relations added.`,
269
- )
270
- this.log("Building remaining id and tag indexes...")
271
- this.buildIndexes()
272
- }
273
-
274
- buildSpatialIndexes() {
275
- this.nodes.buildSpatialIndex()
276
- this.ways.buildSpatialIndex(this.nodes)
277
- }
278
-
279
- extract(bbox: GeoBbox2D) {
280
- if (!this.#indexBuilt) this.buildIndexes()
281
-
282
- const [minLon, minLat, maxLon, maxLat] = bbox
283
- const extracted = new Osmix({
284
- id: this.id,
285
- header: {
286
- ...this.header,
287
- bbox: {
288
- left: minLon,
289
- bottom: minLat,
290
- right: maxLon,
291
- top: maxLat,
292
- },
293
- },
294
- })
295
-
296
- this.log("Selecting nodes within bounding box...")
297
- this.buildSpatialIndexes()
298
- for (const node of this.nodes.sorted()) {
299
- if (
300
- node.lon >= minLon &&
301
- node.lon <= maxLon &&
302
- node.lat >= minLat &&
303
- node.lat <= maxLat
304
- ) {
305
- extracted.nodes.addNode(node)
306
- }
307
- }
308
- extracted.nodes.buildIndex()
309
-
310
- this.log("Selecting ways within bounding box...")
311
- for (const way of this.ways.sorted()) {
312
- const refs = way.refs.filter((ref) => extracted.nodes.ids.has(ref))
313
- if (refs.length > 0) {
314
- extracted.ways.addWay({
315
- ...way,
316
- refs,
317
- })
318
- }
319
- }
320
- extracted.ways.buildIndex()
321
-
322
- this.log("Selecting relations within bounding box...")
323
- for (const relation of this.relations.sorted()) {
324
- const members = relation.members.filter((m) => {
325
- if (m.type === "node") return extracted.nodes.ids.has(m.ref)
326
- if (m.type === "way") return extracted.ways.ids.has(m.ref)
327
- return false
328
- })
329
- if (members.length > 0) {
330
- extracted.relations.addRelation({
331
- ...relation,
332
- members,
333
- })
334
- }
335
- }
336
-
337
- extracted.buildIndexes()
338
- return extracted
339
- }
340
-
341
- get<T extends OsmEntityType>(
342
- type: T,
343
- id: number,
344
- ): OsmEntityTypeMap[T] | undefined {
345
- if (type === "node") return this.nodes.get({ id }) as OsmEntityTypeMap[T]
346
- if (type === "way") return this.ways.get({ id }) as OsmEntityTypeMap[T]
347
- if (type === "relation")
348
- return this.relations.get({ id }) as OsmEntityTypeMap[T]
349
- }
350
-
351
- getById(eid: string): OsmEntity | null {
352
- const [type, sid] = eid.split("/")
353
- const id = Number(sid)
354
- switch (type) {
355
- case "node":
356
- return this.nodes.getById(id)
357
- case "way":
358
- return this.ways.getById(id)
359
- case "relation":
360
- return this.relations.getById(id)
361
- default: {
362
- return null
363
- }
364
- }
365
- }
366
-
367
- getNodesInBbox(bbox: GeoBbox2D, allNodes = false) {
368
- if (!this.#indexBuilt) throw new Error("Osm not finished")
369
- console.time("Osm.getNodesInBbox")
370
- const nodeCandidates = this.nodes.withinBbox(bbox)
371
- const nodePositions = new Float64Array(nodeCandidates.length * 2)
372
- const ids = new IdArrayType(nodeCandidates.length)
373
-
374
- let skipped = 0
375
- nodeCandidates.forEach((nodeIndex, i) => {
376
- // Skip nodes with no tags, likely just a way node
377
- if (!allNodes && this.nodes.tags.cardinality(nodeIndex) === 0) {
378
- skipped++
379
- return
380
- }
381
-
382
- const [lon, lat] = this.nodes.getNodeLonLat({ index: nodeIndex })
383
- ids[i - skipped] = this.nodes.ids.at(nodeIndex)
384
- nodePositions[(i - skipped) * 2] = lon
385
- nodePositions[(i - skipped) * 2 + 1] = lat
386
- })
387
- console.timeEnd("Osm.getNodesInBbox")
388
- return {
389
- ids: ids.subarray(0, nodeCandidates.length - skipped),
390
- positions: nodePositions.slice(0, (nodeCandidates.length - skipped) * 2),
391
- }
392
- }
393
-
394
- getWaysInBbox(bbox: GeoBbox2D) {
395
- console.time("Osm.getWaysInBbox")
396
- const wayCandidates = this.ways.intersects(bbox)
397
- const ids = new IdArrayType(wayCandidates.length)
398
- const wayPositions: Float64Array[] = []
399
- const wayStartIndices = new Uint32Array(wayCandidates.length + 1)
400
- wayStartIndices[0] = 0
401
-
402
- console.time("Osm.getWaysInBbox.loop")
403
- let size = 0
404
- wayCandidates.forEach((wayIndex, i) => {
405
- ids[i] = this.ways.ids.at(wayIndex)
406
- const way = this.ways.getLine(wayIndex, this.nodes)
407
- size += way.length
408
- wayPositions.push(way)
409
- const prevIndex = wayStartIndices[i]
410
- if (prevIndex === undefined) throw Error("Previous index is undefined")
411
- wayStartIndices[i + 1] = prevIndex + way.length / 2
412
- })
413
- console.timeEnd("Osm.getWaysInBbox.loop")
414
- const wayPositionsArray = new Float64Array(size)
415
- let pIndex = 0
416
- for (const way of wayPositions) {
417
- wayPositionsArray.set(way, pIndex)
418
- pIndex += way.length
419
- }
420
-
421
- console.timeEnd("Osm.getWaysInBbox")
422
- return {
423
- ids,
424
- positions: wayPositionsArray,
425
- startIndices: wayStartIndices,
426
- }
427
- }
428
-
429
- getEntityGeoJson(
430
- entity: OsmNode | OsmWay | OsmRelation,
431
- ): OsmixGeoJSONFeature<
432
- GeoJSON.Point | GeoJSON.LineString | GeoJSON.Polygon | GeoJSON.MultiPolygon
433
- > {
434
- if (isNode(entity)) {
435
- return nodeToFeature(entity)
436
- }
437
- if (isWay(entity)) {
438
- return wayToFeature(entity, (ref) =>
439
- this.nodes.getNodeLonLat({ id: ref }),
440
- )
441
- }
442
- if (isRelation(entity)) {
443
- return relationToFeature(entity, (ref) =>
444
- this.nodes.getNodeLonLat({ id: ref }),
445
- )
446
- }
447
- throw new Error("Unknown entity type")
448
- }
449
-
450
- getEntityBbox(entity: OsmNode | OsmWay | OsmRelation): GeoBbox2D {
451
- if (isNode(entity)) {
452
- const [lon, lat] = this.nodes.getNodeLonLat({ id: entity.id })
453
- return [lon, lat, lon, lat] as GeoBbox2D
454
- }
455
- if (isWay(entity)) {
456
- return this.ways.getBbox({ id: entity.id })
457
- }
458
- if (isRelation(entity)) {
459
- const relation = this.relations.getById(entity.id)
460
- if (!relation) throw Error("Relation not found")
461
- const lls: LonLat[] = []
462
- for (const member of relation.members) {
463
- if (member.type === "node") {
464
- const ll = this.nodes.getNodeLonLat({ id: member.ref })
465
- lls.push(ll)
466
- } else if (member.type === "way") {
467
- const wayIndex = this.ways.ids.getIndexFromId(member.ref)
468
- if (wayIndex === -1) throw Error("Way not found")
469
- const wayPositions = this.ways.getCoordinates(wayIndex, this.nodes)
470
- lls.push(...wayPositions)
471
- }
472
- }
473
- return bboxFromLonLats(lls)
474
- }
475
- throw Error("Unknown entity type")
476
- }
477
-
478
- /**
479
- * Get the bounding box of all entities in the OSM index.
480
- */
481
- bbox(): GeoBbox2D {
482
- return this.nodes.bbox
483
- }
484
-
485
- /**
486
- * Create a generator that yields all entities in the OSM index, sorted by type and id.
487
- */
488
- *allEntitiesSorted(): Generator<OsmEntity> {
489
- for (const node of this.nodes.sorted()) {
490
- yield node
491
- }
492
- for (const way of this.ways.sorted()) {
493
- yield way
494
- }
495
- for (const relation of this.relations.sorted()) {
496
- yield relation
497
- }
498
- }
499
-
500
- /**
501
- * Convert the OSM index to a `ReadableStream<OsmPbfHeaderBlock | OsmEntity>`.
502
- */
503
- toEntityStream() {
504
- let headerEnqueued = false
505
- const entityGenerator = this.allEntitiesSorted()
506
- return new ReadableStream<OsmPbfHeaderBlock | OsmEntity>({
507
- pull: async (controller) => {
508
- if (!headerEnqueued) {
509
- controller.enqueue({
510
- ...this.header,
511
- writingprogram: "@osmix/core",
512
- osmosis_replication_timestamp: Date.now(),
513
- })
514
- headerEnqueued = true
515
- }
516
- const block = entityGenerator.next()
517
- if (block.done) {
518
- controller.close()
519
- } else {
520
- controller.enqueue(block.value)
521
- }
522
- },
523
- })
524
- }
525
-
526
- /**
527
- * Convert the OSM index to a `ReadableStream<Uint8Array>` of PBF bytes.
528
- */
529
- toPbfStream() {
530
- return this.toEntityStream()
531
- .pipeThrough(new OsmJsonToBlocksTransformStream())
532
- .pipeThrough(new OsmBlocksToPbfBytesTransformStream())
533
- }
534
-
535
- /**
536
- * Convert the OSM index to an in memory PBF ArrayBuffer.
537
- */
538
- async toPbfBuffer() {
539
- const chunks: Uint8Array[] = []
540
- let byteLength = 0
541
- const writable = new WritableStream<Uint8Array>({
542
- write(chunk) {
543
- chunks.push(chunk)
544
- byteLength += chunk.byteLength
545
- },
546
- })
547
- await this.toPbfStream().pipeTo(writable)
548
- const combined = new Uint8Array(byteLength)
549
- let offset = 0
550
- for (const chunk of chunks) {
551
- combined.set(chunk, offset)
552
- offset += chunk.byteLength
553
- }
554
- return combined.buffer
555
- }
556
- }
@@ -1,29 +0,0 @@
1
- import { getFixtureFile } from "@osmix/shared/test/fixtures"
2
- import type { GeoBbox2D } from "@osmix/shared/types"
3
- import { beforeAll, bench, describe } from "vitest"
4
- import { Osmix } from "../src/osmix"
5
-
6
- const MONACO_BBOX: GeoBbox2D = [7.4053929, 43.7232244, 7.4447259, 43.7543687]
7
- // const SEATTLE_BBOX: GeoBbox2D = [-122.33, 47.48, -122.29, 47.52]
8
-
9
- const BBOX = MONACO_BBOX
10
- const PBF = "monaco.pbf"
11
-
12
- let buffer: Uint8Array<ArrayBufferLike>
13
-
14
- beforeAll(async () => {
15
- buffer = await getFixtureFile(PBF)
16
- })
17
-
18
- describe("simple extract benchmark", () => {
19
- bench("two-step parse then extract", async () => {
20
- const data = buffer.slice(0)
21
- const full = await Osmix.fromPbf(data)
22
- full.extract(BBOX)
23
- })
24
-
25
- bench("streaming extract during parse", async () => {
26
- const data = buffer.slice(0)
27
- await Osmix.fromPbf(data, { extractBbox: BBOX })
28
- })
29
- })