@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/entities.ts CHANGED
@@ -1,59 +1,151 @@
1
- import type { OsmEntity, OsmEntityType, OsmTags } from "@osmix/json"
2
- import { type IdOrIndex, Ids, type IdsTransferables } from "./ids"
3
- import type StringTable from "./stringtable"
4
- import { Tags, type TagsTransferables } from "./tags"
1
+ /**
2
+ * Base class for OSM entity collections.
3
+ *
4
+ * Provides common ID and tag storage, streaming iteration, and sorted access.
5
+ * Subclasses implement entity-specific storage and spatial indexing.
6
+ *
7
+ * @module
8
+ */
5
9
 
6
- export interface EntitiesTransferables
7
- extends IdsTransferables,
8
- TagsTransferables {}
10
+ import type {
11
+ GeoBbox2D,
12
+ OsmEntity,
13
+ OsmEntityType,
14
+ OsmTags,
15
+ } from "@osmix/shared/types"
16
+ import type { IdOrIndex, Ids, IdsTransferables } from "./ids"
17
+ import type { Tags, TagsTransferables } from "./tags"
18
+ import type { BufferType } from "./typed-arrays"
9
19
 
20
+ /**
21
+ * Serializable representation of an Entities collection for worker transfer.
22
+ * Combines ID and tag transferables; subclasses add entity-specific data.
23
+ */
24
+ export interface EntitiesTransferables<T extends BufferType = BufferType>
25
+ extends IdsTransferables<T>,
26
+ TagsTransferables<T> {}
27
+
28
+ /**
29
+ * Abstract base for typed entity collections.
30
+ *
31
+ * Lifecycle:
32
+ * 1. **Ingest**: `addEntity()` (no lookups).
33
+ * 2. **Finalize**: `buildIndex()`.
34
+ * 3. **Query**: Lookups and iteration enabled.
35
+ */
10
36
  export abstract class Entities<T extends OsmEntity> {
37
+ /** The type of entity stored in this collection ("node", "way", or "relation"). */
11
38
  indexType: OsmEntityType
12
- stringTable: StringTable
39
+ /** ID storage and lookup */
13
40
  ids: Ids
41
+ /** Tag storage and search */
14
42
  tags: Tags
15
43
 
16
- private indexBuilt = false
44
+ /** Whether buildIndex() has been called */
45
+ protected indexBuilt = false
17
46
 
18
- constructor(
19
- indexType: OsmEntityType,
20
- stringTable: StringTable,
21
- ids?: Ids,
22
- tags?: Tags,
23
- ) {
24
- this.stringTable = stringTable
47
+ /**
48
+ * Create a new Entities collection.
49
+ * @param indexType - The entity type ("node", "way", or "relation").
50
+ * @param ids - The ID storage instance.
51
+ * @param tags - The tag storage instance.
52
+ */
53
+ constructor(indexType: OsmEntityType, ids: Ids, tags: Tags) {
25
54
  this.indexType = indexType
26
- this.ids = ids ?? new Ids()
27
- this.tags = tags ?? new Tags(stringTable)
55
+ this.ids = ids
56
+ this.tags = tags
28
57
  }
29
58
 
30
- get isReady() {
31
- return this.ids.isReady && this.tags.isReady && this.indexBuilt
59
+ /**
60
+ * Get transferable objects for passing to another thread.
61
+ */
62
+ transferables(): EntitiesTransferables {
63
+ return {
64
+ ...this.ids.transferables(),
65
+ ...this.tags.transferables(),
66
+ }
32
67
  }
33
68
 
69
+ /**
70
+ * Check if the index is built and ready for use.
71
+ */
72
+ isReady() {
73
+ return this.ids.isReady() && this.tags.isReady() && this.indexBuilt
74
+ }
75
+
76
+ /** Number of entities in this collection. */
34
77
  get size() {
35
78
  return this.ids.size
36
79
  }
37
80
 
81
+ /**
82
+ * Compact entity-specific typed arrays.
83
+ * Called by `buildIndex()` after ID and tag indexes are built.
84
+ * @abstract
85
+ */
38
86
  abstract buildEntityIndex(): void
39
87
 
88
+ /**
89
+ * Finalize indexes.
90
+ * Must be called after adding entities and before querying.
91
+ */
40
92
  buildIndex() {
41
- console.time(`${this.indexType}Index.finish`)
93
+ if (this.indexBuilt) return
94
+ console.time(`${this.indexType}Index.buildIndex`)
42
95
  this.ids.buildIndex()
43
96
  this.tags.buildIndex()
44
97
  this.buildEntityIndex()
45
98
  this.indexBuilt = true
46
- console.timeEnd(`${this.indexType}Index.finish`)
99
+ console.timeEnd(`${this.indexType}Index.buildIndex`)
47
100
  }
48
101
 
102
+ /**
103
+ * Get the bounding box of an entity.
104
+ * @param idOrIndex - Entity identifier (by ID or internal index).
105
+ * @returns Geographic bounding box [minLon, minLat, maxLon, maxLat].
106
+ * @abstract
107
+ */
108
+ abstract getEntityBbox(idOrIndex: IdOrIndex): GeoBbox2D
109
+
110
+ /**
111
+ * Reconstruct a full entity object from index data.
112
+ * @param index - Internal array index.
113
+ * @param id - OSM entity ID.
114
+ * @param tags - Optional pre-fetched tags.
115
+ * @returns The complete entity object.
116
+ * @abstract
117
+ */
49
118
  abstract getFullEntity(index: number, id: number, tags?: OsmTags): T
50
119
 
120
+ /**
121
+ * Add an entity to the index. Tags can be provided as an array of keys and values, or as an object.
122
+ */
123
+ addEntity(id: number, tags: number[], values: number[]): number
124
+ addEntity(id: number, tags: OsmTags): number
125
+ addEntity(id: number, tags: OsmTags | number[], values?: number[]): number {
126
+ const entityIndex = this.ids.add(id)
127
+ if (Array.isArray(tags)) {
128
+ if (values === undefined)
129
+ throw Error("Values are required when tags is an array")
130
+ this.tags.addTagKeysAndValues(entityIndex, tags, values)
131
+ } else {
132
+ this.tags.addTags(entityIndex, tags)
133
+ }
134
+ return entityIndex
135
+ }
136
+
137
+ /**
138
+ * Get an entity by ID or index.
139
+ */
51
140
  get(idOrIndex: IdOrIndex): T | null {
52
141
  const [index, id] = this.ids.idOrIndex(idOrIndex)
53
142
  if (index === -1) return null
54
143
  return this.getFullEntity(index, id, this.tags.getTags(index))
55
144
  }
56
145
 
146
+ /**
147
+ * Get an entity by index.
148
+ */
57
149
  getByIndex(index: number): T {
58
150
  return this.getFullEntity(
59
151
  index,
@@ -62,6 +154,9 @@ export abstract class Entities<T extends OsmEntity> {
62
154
  )
63
155
  }
64
156
 
157
+ /**
158
+ * Get multiple entities by their indexes.
159
+ */
65
160
  getEntitiesByIndex(indexes: number[]): T[] {
66
161
  const entities: T[] = []
67
162
  for (const index of indexes) {
@@ -72,12 +167,18 @@ export abstract class Entities<T extends OsmEntity> {
72
167
  return entities
73
168
  }
74
169
 
170
+ /**
171
+ * Iterate over all entities in the index.
172
+ */
75
173
  *[Symbol.iterator](): Generator<T> {
76
174
  for (let i = 0; i < this.size; i++) {
77
175
  yield this.getFullEntity(i, this.ids.at(i), this.tags.getTags(i))
78
176
  }
79
177
  }
80
178
 
179
+ /**
180
+ * Get an entity by ID.
181
+ */
81
182
  getById(id: number): T | null {
82
183
  const index = this.ids.getIndexFromId(id)
83
184
  if (index !== -1)
@@ -85,6 +186,9 @@ export abstract class Entities<T extends OsmEntity> {
85
186
  return null
86
187
  }
87
188
 
189
+ /**
190
+ * Iterate over entities sorted by ID.
191
+ */
88
192
  *sorted(): Generator<T> {
89
193
  for (const id of this.ids.sorted) {
90
194
  const index = this.ids.getIndexFromId(id)
@@ -92,4 +196,16 @@ export abstract class Entities<T extends OsmEntity> {
92
196
  yield this.getFullEntity(index, id, this.tags.getTags(index))
93
197
  }
94
198
  }
199
+
200
+ /**
201
+ * Search for entities with a specific tag key and optional value.
202
+ */
203
+ search(key: string, val?: string): T[] {
204
+ const keyIndex = this.tags.find(key)
205
+ const entities = this.tags
206
+ .hasKey(keyIndex)
207
+ .map((index) => this.getByIndex(index))
208
+ if (val === undefined) return entities
209
+ return entities.filter((entity) => entity.tags?.[key] === val)
210
+ }
95
211
  }
package/src/ids.ts CHANGED
@@ -1,92 +1,130 @@
1
+ /**
2
+ * ID storage and lookup for OSM entities.
3
+ *
4
+ * Uses a two-level binary search (anchor array + block search) to map 64-bit OSM IDs
5
+ * to internal array indices. Balances memory usage with O(log n) lookup speed.
6
+ *
7
+ * @module
8
+ */
9
+
1
10
  import { assertValue } from "@osmix/shared/assert"
2
11
  import {
3
12
  BufferConstructor,
4
13
  type BufferType,
5
- ResizeableTypedArray,
14
+ ResizeableTypedArray as RTA,
6
15
  } from "./typed-arrays"
7
16
 
17
+ /**
18
+ * Union type for looking up entities by either OSM ID or internal array index.
19
+ */
8
20
  export type IdOrIndex = { id: number } | { index: number }
9
21
 
22
+ /**
23
+ * Number of IDs per anchor block for the two-level binary search.
24
+ * Smaller values increase anchor array size but speed up block-level search;
25
+ * larger values reduce anchor overhead but slow the final search.
26
+ */
10
27
  const BLOCK_SIZE = 256
11
28
 
12
- export interface IdsTransferables {
13
- ids: BufferType
14
- sortedIds: BufferType
15
- sortedIdPositionToIndex: BufferType
16
- anchors: BufferType
29
+ /**
30
+ * Serializable state for worker transfer.
31
+ */
32
+ export interface IdsTransferables<T extends BufferType = BufferType> {
33
+ /** Entity IDs in insertion order. */
34
+ ids: T
35
+ /** Sorted IDs for binary search (aliases `ids` if already sorted). */
36
+ sortedIds: T
37
+ /** Maps sorted position → original insertion index. */
38
+ sortedIdPositionToIndex: T
39
+ /** Anchor array: every BLOCK_SIZE-th sorted ID. */
40
+ anchors: T
41
+ /** True if IDs were inserted in ascending order. */
17
42
  idsAreSorted: boolean
18
43
  }
19
44
 
20
45
  /**
21
- * Efficiently store and lookup IDs.
46
+ * Efficiently store and lookup OSM entity IDs.
22
47
  *
23
- * This is used to store IDs in a sorted array and then use binary search to find the index of an ID.
24
- * Maps max out at 2^32 IDs.
48
+ * Stores 64-bit IDs in a Float64Array and maintains a sorted index for O(log n) lookups.
49
+ * Max capacity: ~2^32 entities.
25
50
  */
26
51
  export class Ids {
27
- private ids: ResizeableTypedArray<Float64Array>
52
+ /** All IDs in insertion order */
53
+ private ids: RTA<Float64Array>
54
+ /** Whether buildIndex() has been called */
28
55
  private indexBuilt = false
56
+ /** True if IDs were added in ascending order (allows index optimization) */
29
57
  private idsAreSorted = true
58
+ /** Sorted view of IDs for binary search */
30
59
  private idsSorted: Float64Array
60
+ /** Maps position in sorted array → original insertion index */
31
61
  private sortedIdPositionToIndex: Uint32Array
62
+ /** Anchor array for two-level binary search: every BLOCK_SIZE-th sorted ID */
32
63
  private anchors: Float64Array
33
64
 
34
- static from({
35
- ids,
36
- sortedIds,
37
- sortedIdPositionToIndex,
38
- anchors,
39
- idsAreSorted,
40
- }: IdsTransferables) {
41
- const idIndex = new Ids()
42
- idIndex.ids = ResizeableTypedArray.from(Float64Array, ids)
43
- idIndex.idsSorted = new Float64Array(sortedIds)
44
- idIndex.sortedIdPositionToIndex = new Uint32Array(sortedIdPositionToIndex)
45
- idIndex.anchors = new Float64Array(anchors)
46
- idIndex.indexBuilt = true
47
- idIndex.idsAreSorted = idsAreSorted
48
- return idIndex
49
- }
50
-
51
- constructor() {
52
- this.ids = new ResizeableTypedArray(Float64Array)
53
- this.idsSorted = new Float64Array(new BufferConstructor(0))
54
- this.sortedIdPositionToIndex = new Uint32Array(new BufferConstructor(0))
55
- this.anchors = new Float64Array(new BufferConstructor(0))
56
- }
57
-
58
- transferables(): IdsTransferables {
59
- return {
60
- ids: this.ids.array.buffer,
61
- sortedIds: this.idsSorted.buffer,
62
- sortedIdPositionToIndex: this.sortedIdPositionToIndex.buffer,
63
- anchors: this.anchors.buffer,
64
- idsAreSorted: this.idsAreSorted,
65
+ /**
66
+ * Create a new Ids index.
67
+ * @param transferables - Optional serialized state to reconstruct from.
68
+ */
69
+ constructor(transferables?: IdsTransferables) {
70
+ if (transferables) {
71
+ this.ids = RTA.from(Float64Array, transferables.ids)
72
+ this.idsSorted = new Float64Array(transferables.sortedIds)
73
+ this.sortedIdPositionToIndex = new Uint32Array(
74
+ transferables.sortedIdPositionToIndex,
75
+ )
76
+ this.anchors = new Float64Array(transferables.anchors)
77
+ this.idsAreSorted = transferables.idsAreSorted
78
+ this.indexBuilt = true
79
+ } else {
80
+ this.ids = new RTA(Float64Array)
81
+ this.idsSorted = new Float64Array(new BufferConstructor(0))
82
+ this.sortedIdPositionToIndex = new Uint32Array(new BufferConstructor(0))
83
+ this.anchors = new Float64Array(new BufferConstructor(0))
65
84
  }
66
85
  }
67
86
 
87
+ /** Number of IDs stored in this index. */
68
88
  get size() {
69
89
  return this.ids.length
70
90
  }
71
91
 
72
- get isReady() {
92
+ /** Returns true if buildIndex() has been called and lookups are enabled. */
93
+ isReady() {
73
94
  return this.indexBuilt
74
95
  }
75
96
 
97
+ /** Returns true if IDs were inserted in ascending order. */
76
98
  isSorted() {
77
99
  return this.idsAreSorted
78
100
  }
79
101
 
80
- add(id: number): void {
102
+ /**
103
+ * Add an ID to the index.
104
+ * @param id - The OSM entity ID to add.
105
+ * @returns The internal array index where this ID was stored.
106
+ * @throws If the index has already been built.
107
+ */
108
+ add(id: number): number {
81
109
  if (this.indexBuilt) throw Error("ID index already built.")
82
110
  if (this.ids.length > 0 && id < this.ids.at(-1)) this.idsAreSorted = false
83
- this.ids.push(id)
111
+ return this.ids.push(id)
84
112
  }
85
113
 
114
+ /**
115
+ * Get the ID at a specific internal index.
116
+ * @param index - The internal array index.
117
+ * @returns The OSM entity ID at that index.
118
+ */
86
119
  at(index: number): number {
87
120
  return this.ids.at(index)
88
121
  }
89
122
 
123
+ /**
124
+ * Check if an ID exists in this index.
125
+ * @param id - The OSM entity ID to check.
126
+ * @returns True if the ID exists in this index.
127
+ */
90
128
  has(id: number): boolean {
91
129
  return this.getIndexFromId(id) !== -1
92
130
  }
@@ -158,7 +196,13 @@ export class Ids {
158
196
  this.indexBuilt = true
159
197
  }
160
198
 
161
- // Lookup id → index
199
+ /**
200
+ * Look up the internal array index for an OSM entity ID.
201
+ *
202
+ * @param id - The OSM entity ID to look up.
203
+ * @returns The internal array index, or -1 if not found.
204
+ * @throws If the index has not been built.
205
+ */
162
206
  getIndexFromId(id: number): number {
163
207
  if (!this.indexBuilt) throw Error("IdIndex not built.")
164
208
 
@@ -204,7 +248,35 @@ export class Ids {
204
248
  return [i.index, this.at(i.index)]
205
249
  }
206
250
 
251
+ /** Returns the sorted array of IDs for iteration. */
207
252
  get sorted() {
208
253
  return this.idsSorted
209
254
  }
255
+
256
+ /**
257
+ * Get transferable buffers for passing to another thread.
258
+ * @returns Serializable representation of this index.
259
+ */
260
+ transferables(): IdsTransferables {
261
+ return {
262
+ ids: this.ids.array.buffer,
263
+ sortedIds: this.idsSorted.buffer,
264
+ sortedIdPositionToIndex: this.sortedIdPositionToIndex.buffer,
265
+ anchors: this.anchors.buffer,
266
+ idsAreSorted: this.idsAreSorted,
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Get the approximate memory requirements for a given number of IDs in bytes.
272
+ */
273
+ static getBytesRequired(count: number) {
274
+ if (count === 0) return 0
275
+ return (
276
+ count * Float64Array.BYTES_PER_ELEMENT + // ids
277
+ count * Float64Array.BYTES_PER_ELEMENT + // sortedIds
278
+ count * Uint32Array.BYTES_PER_ELEMENT + // sortedIdPositionToIndex
279
+ Math.ceil(count / BLOCK_SIZE) * Float64Array.BYTES_PER_ELEMENT // anchors
280
+ )
281
+ }
210
282
  }
package/src/index.ts CHANGED
@@ -1,7 +1,36 @@
1
+ /**
2
+ * @osmix/core - In-memory OSM entity storage with spatial indexing.
3
+ *
4
+ * Efficiently stores and queries OpenStreetMap entities (nodes, ways, relations).
5
+ *
6
+ * Features:
7
+ * - **Memory-efficient**: Uses typed arrays and Int32Array microdegrees.
8
+ * - **Spatial indexing**: KDBush (points) and Flatbush (bboxes) for fast geographic queries.
9
+ * - **Worker-ready**: Zero-copy transfer via `transferables()`.
10
+ * - **Tag indexing**: Fast reverse lookup by tag key.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { Osm } from "@osmix/core"
15
+ * const osm = new Osm({ id: "example" })
16
+ * osm.nodes.addNode({ id: 1, lon: -122.4, lat: 47.6, tags: { name: "Seattle" } })
17
+ * osm.buildIndexes()
18
+ * osm.buildSpatialIndexes()
19
+ * const nearby = osm.nodes.findIndexesWithinRadius(-122.4, 47.6, 10)
20
+ * ```
21
+ *
22
+ * @module @osmix/core
23
+ */
24
+
1
25
  /// <reference path="./types/kdbush.d.ts" />
26
+ /// <reference path="./types/geokdbush.d.ts" />
27
+ /// <reference path="./types/geoflatbush.d.ts" />
2
28
 
3
- export { Nodes } from "./nodes"
4
- export { Osmix } from "./osmix"
5
- export { Relations } from "./relations"
6
- export { throttle } from "./utils"
7
- export { Ways } from "./ways"
29
+ export * from "./nodes"
30
+ export * from "./osm"
31
+ export * from "./relations"
32
+ export * from "./stringtable"
33
+ export * from "./tags"
34
+ export { BufferConstructor, type BufferType } from "./typed-arrays"
35
+ export * from "./utils" // TODO Move into shared?
36
+ export * from "./ways"