@osmix/geojson 0.0.15 → 0.0.16
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 +24 -0
- package/LICENSE +21 -0
- package/README.md +50 -51
- package/dist/entity-to-feature.d.ts +7 -7
- package/dist/entity-to-feature.d.ts.map +1 -1
- package/dist/entity-to-feature.js +27 -11
- package/dist/entity-to-feature.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/osm-from-geojson.d.ts +2 -2
- package/dist/osm-from-geojson.d.ts.map +1 -1
- package/dist/osm-from-geojson.js +6 -6
- package/dist/osm-from-geojson.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js.map +1 -1
- package/osmix-geojson-0.0.16.tgz +0 -0
- package/package.json +31 -31
- package/src/entity-to-feature.ts +309 -314
- package/src/index.ts +3 -3
- package/src/osm-from-geojson.ts +266 -287
- package/src/types.ts +31 -35
- package/src/utils.ts +25 -27
- package/test/entity-to-feature.test.ts +56 -59
- package/test/osm-from-geojson.test.ts +855 -866
- package/tsconfig.build.json +6 -6
- package/tsconfig.json +7 -7
package/src/entity-to-feature.ts
CHANGED
|
@@ -7,36 +7,28 @@
|
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import type {
|
|
10
|
+
import type { OsmReader } from "@osmix/core/contracts";
|
|
11
|
+
import { buildRelationRings, getWayMembersByRole } from "@osmix/geo/relation-multipolygon";
|
|
12
|
+
import { wayIsArea } from "@osmix/geo/way-is-area";
|
|
13
|
+
import type { LonLat, OsmEntity, OsmNode, OsmRelation, OsmWay } from "@osmix/types";
|
|
11
14
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} from "@osmix/
|
|
17
|
-
import {
|
|
18
|
-
buildRelationRings,
|
|
19
|
-
getWayMembersByRole,
|
|
20
|
-
} from "@osmix/shared/relation-multipolygon"
|
|
21
|
-
import type {
|
|
22
|
-
LonLat,
|
|
23
|
-
OsmEntity,
|
|
24
|
-
OsmNode,
|
|
25
|
-
OsmRelation,
|
|
26
|
-
OsmWay,
|
|
27
|
-
} from "@osmix/shared/types"
|
|
28
|
-
import { isNode, isRelation, isWay } from "@osmix/shared/utils"
|
|
29
|
-
import { wayIsArea } from "@osmix/shared/way-is-area"
|
|
15
|
+
buildRelationLineStrings,
|
|
16
|
+
collectRelationPoints,
|
|
17
|
+
getRelationKind,
|
|
18
|
+
isAreaRelation,
|
|
19
|
+
} from "@osmix/types/relation-kind";
|
|
20
|
+
import { isNode, isRelation, isWay } from "@osmix/types/utils";
|
|
30
21
|
import type {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
} from "geojson"
|
|
39
|
-
|
|
22
|
+
GeometryCollection,
|
|
23
|
+
LineString,
|
|
24
|
+
MultiLineString,
|
|
25
|
+
MultiPoint,
|
|
26
|
+
MultiPolygon,
|
|
27
|
+
Point,
|
|
28
|
+
Polygon,
|
|
29
|
+
} from "geojson";
|
|
30
|
+
|
|
31
|
+
import type { OsmGeoJSONFeature } from "./types.ts";
|
|
40
32
|
|
|
41
33
|
/**
|
|
42
34
|
* Convert an OSM node to a GeoJSON Point feature.
|
|
@@ -51,20 +43,20 @@ import type { OsmGeoJSONFeature } from "./types.ts"
|
|
|
51
43
|
* ```
|
|
52
44
|
*/
|
|
53
45
|
export function nodeToFeature(node: OsmNode): OsmGeoJSONFeature<Point> {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
46
|
+
return {
|
|
47
|
+
type: "Feature",
|
|
48
|
+
id: node.id,
|
|
49
|
+
geometry: {
|
|
50
|
+
type: "Point",
|
|
51
|
+
coordinates: [node.lon, node.lat],
|
|
52
|
+
},
|
|
53
|
+
properties: {
|
|
54
|
+
id: node.id,
|
|
55
|
+
type: "node",
|
|
56
|
+
...node.info,
|
|
57
|
+
...node.tags,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
68
60
|
}
|
|
69
61
|
|
|
70
62
|
/**
|
|
@@ -74,7 +66,7 @@ export function nodeToFeature(node: OsmNode): OsmGeoJSONFeature<Point> {
|
|
|
74
66
|
* area-indicating tags (building, landuse, etc.) and ring closure.
|
|
75
67
|
*
|
|
76
68
|
* @param way - OSM way with id, refs, and optional tags.
|
|
77
|
-
* @param refToPosition - Function to resolve node ID to
|
|
69
|
+
* @param refToPosition - Function to resolve node ID to coordinates, or null for a missing node.
|
|
78
70
|
* @returns GeoJSON LineString or Polygon Feature with OSM properties.
|
|
79
71
|
*
|
|
80
72
|
* @example
|
|
@@ -83,28 +75,34 @@ export function nodeToFeature(node: OsmNode): OsmGeoJSONFeature<Point> {
|
|
|
83
75
|
* ```
|
|
84
76
|
*/
|
|
85
77
|
export function wayToFeature(
|
|
86
|
-
|
|
87
|
-
|
|
78
|
+
way: OsmWay,
|
|
79
|
+
refToPosition: (id: number) => [number, number] | null | undefined,
|
|
88
80
|
): OsmGeoJSONFeature<LineString | Polygon> {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
81
|
+
const resolvedCoordinates: [number, number][] = [];
|
|
82
|
+
for (const ref of way.refs) {
|
|
83
|
+
const position = refToPosition(ref);
|
|
84
|
+
if (!position) throw Error(`Node reference missing for way ${way.id}`);
|
|
85
|
+
resolvedCoordinates.push(position);
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
type: "Feature",
|
|
89
|
+
id: way.id,
|
|
90
|
+
geometry: wayIsArea(way)
|
|
91
|
+
? {
|
|
92
|
+
type: "Polygon",
|
|
93
|
+
coordinates: [resolvedCoordinates],
|
|
94
|
+
}
|
|
95
|
+
: {
|
|
96
|
+
type: "LineString",
|
|
97
|
+
coordinates: resolvedCoordinates,
|
|
98
|
+
},
|
|
99
|
+
properties: {
|
|
100
|
+
id: way.id,
|
|
101
|
+
type: "way",
|
|
102
|
+
...way.info,
|
|
103
|
+
...way.tags,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
108
106
|
}
|
|
109
107
|
|
|
110
108
|
/**
|
|
@@ -117,7 +115,7 @@ export function wayToFeature(
|
|
|
117
115
|
* - **Other**: GeometryCollection (empty for logical relations)
|
|
118
116
|
*
|
|
119
117
|
* @param relation - OSM relation with id, members, and optional tags.
|
|
120
|
-
* @param refToPosition - Function to resolve node ID to
|
|
118
|
+
* @param refToPosition - Function to resolve node ID to coordinates, or null for a missing node.
|
|
121
119
|
* @param getWay - Optional function to resolve way ID to OsmWay (required for polygons/lines).
|
|
122
120
|
* @returns GeoJSON Feature with appropriate geometry type.
|
|
123
121
|
*
|
|
@@ -131,252 +129,245 @@ export function wayToFeature(
|
|
|
131
129
|
* ```
|
|
132
130
|
*/
|
|
133
131
|
export function relationToFeature(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
relation: OsmRelation,
|
|
133
|
+
refToPosition: (id: number) => [number, number] | null | undefined,
|
|
134
|
+
getWay?: (wayId: number) => OsmWay | null,
|
|
137
135
|
): OsmGeoJSONFeature<
|
|
138
|
-
|
|
139
|
-
| MultiPolygon
|
|
140
|
-
| LineString
|
|
141
|
-
| MultiLineString
|
|
142
|
-
| Point
|
|
143
|
-
| MultiPoint
|
|
144
|
-
| GeometryCollection
|
|
136
|
+
Polygon | MultiPolygon | LineString | MultiLineString | Point | MultiPoint | GeometryCollection
|
|
145
137
|
> {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
138
|
+
const getNodeCoordinates = (nodeId: number): LonLat | undefined => {
|
|
139
|
+
const pos = refToPosition(nodeId);
|
|
140
|
+
return pos ? [pos[0], pos[1]] : undefined;
|
|
141
|
+
};
|
|
150
142
|
|
|
151
|
-
|
|
143
|
+
const kind = getRelationKind(relation);
|
|
152
144
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
145
|
+
// Handle area relations (multipolygon, boundary)
|
|
146
|
+
if (isAreaRelation(relation) && getWay) {
|
|
147
|
+
const rings = buildRelationRings(relation, getWay, getNodeCoordinates);
|
|
156
148
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
149
|
+
if (rings.length === 0) {
|
|
150
|
+
// Fallback to simple MultiPolygon if we can't build rings
|
|
151
|
+
return {
|
|
152
|
+
type: "Feature",
|
|
153
|
+
id: relation.id,
|
|
154
|
+
geometry: {
|
|
155
|
+
type: "MultiPolygon",
|
|
156
|
+
coordinates: [],
|
|
157
|
+
},
|
|
158
|
+
properties: {
|
|
159
|
+
id: relation.id,
|
|
160
|
+
type: "relation",
|
|
161
|
+
...relation.info,
|
|
162
|
+
...relation.tags,
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
174
166
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
167
|
+
// If only one polygon, return Polygon; otherwise MultiPolygon
|
|
168
|
+
if (rings.length === 1) {
|
|
169
|
+
return {
|
|
170
|
+
type: "Feature",
|
|
171
|
+
id: relation.id,
|
|
172
|
+
geometry: {
|
|
173
|
+
type: "Polygon",
|
|
174
|
+
coordinates: rings[0]!,
|
|
175
|
+
},
|
|
176
|
+
properties: {
|
|
177
|
+
id: relation.id,
|
|
178
|
+
type: "relation",
|
|
179
|
+
...relation.info,
|
|
180
|
+
...relation.tags,
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
}
|
|
192
184
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
185
|
+
return {
|
|
186
|
+
type: "Feature",
|
|
187
|
+
id: relation.id,
|
|
188
|
+
geometry: {
|
|
189
|
+
type: "MultiPolygon",
|
|
190
|
+
coordinates: rings,
|
|
191
|
+
},
|
|
192
|
+
properties: {
|
|
193
|
+
id: relation.id,
|
|
194
|
+
type: "relation",
|
|
195
|
+
...relation.info,
|
|
196
|
+
...relation.tags,
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
}
|
|
208
200
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
relation,
|
|
213
|
-
getWay,
|
|
214
|
-
getNodeCoordinates,
|
|
215
|
-
)
|
|
201
|
+
// Handle line relations (route, multilinestring)
|
|
202
|
+
if (kind === "line" && getWay) {
|
|
203
|
+
const lineStrings = buildRelationLineStrings(relation, getWay, getNodeCoordinates);
|
|
216
204
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
205
|
+
if (lineStrings.length === 0) {
|
|
206
|
+
return {
|
|
207
|
+
type: "Feature",
|
|
208
|
+
id: relation.id,
|
|
209
|
+
geometry: {
|
|
210
|
+
type: "MultiLineString",
|
|
211
|
+
coordinates: [],
|
|
212
|
+
},
|
|
213
|
+
properties: {
|
|
214
|
+
id: relation.id,
|
|
215
|
+
type: "relation",
|
|
216
|
+
...relation.info,
|
|
217
|
+
...relation.tags,
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
}
|
|
233
221
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
222
|
+
if (lineStrings.length === 1) {
|
|
223
|
+
return {
|
|
224
|
+
type: "Feature",
|
|
225
|
+
id: relation.id,
|
|
226
|
+
geometry: {
|
|
227
|
+
type: "LineString",
|
|
228
|
+
coordinates: lineStrings[0]!,
|
|
229
|
+
},
|
|
230
|
+
properties: {
|
|
231
|
+
id: relation.id,
|
|
232
|
+
type: "relation",
|
|
233
|
+
...relation.info,
|
|
234
|
+
...relation.tags,
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
}
|
|
250
238
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
239
|
+
return {
|
|
240
|
+
type: "Feature",
|
|
241
|
+
id: relation.id,
|
|
242
|
+
geometry: {
|
|
243
|
+
type: "MultiLineString",
|
|
244
|
+
coordinates: lineStrings,
|
|
245
|
+
},
|
|
246
|
+
properties: {
|
|
247
|
+
id: relation.id,
|
|
248
|
+
type: "relation",
|
|
249
|
+
...relation.info,
|
|
250
|
+
...relation.tags,
|
|
251
|
+
},
|
|
252
|
+
};
|
|
253
|
+
}
|
|
266
254
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
255
|
+
// Handle point relations (multipoint)
|
|
256
|
+
if (kind === "point") {
|
|
257
|
+
const points = collectRelationPoints(relation, getNodeCoordinates);
|
|
270
258
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
259
|
+
if (points.length === 0) {
|
|
260
|
+
return {
|
|
261
|
+
type: "Feature",
|
|
262
|
+
id: relation.id,
|
|
263
|
+
geometry: {
|
|
264
|
+
type: "MultiPoint",
|
|
265
|
+
coordinates: [],
|
|
266
|
+
},
|
|
267
|
+
properties: {
|
|
268
|
+
id: relation.id,
|
|
269
|
+
type: "relation",
|
|
270
|
+
...relation.info,
|
|
271
|
+
...relation.tags,
|
|
272
|
+
},
|
|
273
|
+
};
|
|
274
|
+
}
|
|
287
275
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
276
|
+
if (points.length === 1) {
|
|
277
|
+
return {
|
|
278
|
+
type: "Feature",
|
|
279
|
+
id: relation.id,
|
|
280
|
+
geometry: {
|
|
281
|
+
type: "Point",
|
|
282
|
+
coordinates: points[0]!,
|
|
283
|
+
},
|
|
284
|
+
properties: {
|
|
285
|
+
id: relation.id,
|
|
286
|
+
type: "relation",
|
|
287
|
+
...relation.info,
|
|
288
|
+
...relation.tags,
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
}
|
|
304
292
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
293
|
+
return {
|
|
294
|
+
type: "Feature",
|
|
295
|
+
id: relation.id,
|
|
296
|
+
geometry: {
|
|
297
|
+
type: "MultiPoint",
|
|
298
|
+
coordinates: points,
|
|
299
|
+
},
|
|
300
|
+
properties: {
|
|
301
|
+
id: relation.id,
|
|
302
|
+
type: "relation",
|
|
303
|
+
...relation.info,
|
|
304
|
+
...relation.tags,
|
|
305
|
+
},
|
|
306
|
+
};
|
|
307
|
+
}
|
|
320
308
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
309
|
+
// Fallback for logical relations or when getWay is not provided
|
|
310
|
+
// Return GeometryCollection or null geometry for logic-only relations
|
|
311
|
+
if (kind === "logic" || kind === "super") {
|
|
312
|
+
return {
|
|
313
|
+
type: "Feature",
|
|
314
|
+
id: relation.id,
|
|
315
|
+
geometry: {
|
|
316
|
+
type: "GeometryCollection",
|
|
317
|
+
geometries: [],
|
|
318
|
+
},
|
|
319
|
+
properties: {
|
|
320
|
+
id: relation.id,
|
|
321
|
+
type: "relation",
|
|
322
|
+
...relation.info,
|
|
323
|
+
...relation.tags,
|
|
324
|
+
},
|
|
325
|
+
};
|
|
326
|
+
}
|
|
339
327
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
328
|
+
// Final fallback: try to create a simple representation from way members
|
|
329
|
+
if (getWay) {
|
|
330
|
+
const { outer } = getWayMembersByRole(relation);
|
|
331
|
+
const coordinates: [number, number][][][] = [];
|
|
344
332
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
333
|
+
if (outer.length > 0) {
|
|
334
|
+
const outerCoordinates = outer
|
|
335
|
+
.map((member) => refToPosition(member.ref))
|
|
336
|
+
.filter((position): position is [number, number] => position != null);
|
|
337
|
+
if (outerCoordinates.length > 0) coordinates.push([outerCoordinates]);
|
|
338
|
+
}
|
|
348
339
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
340
|
+
return {
|
|
341
|
+
type: "Feature",
|
|
342
|
+
id: relation.id,
|
|
343
|
+
geometry: {
|
|
344
|
+
type: "MultiPolygon",
|
|
345
|
+
coordinates: coordinates.length > 0 ? coordinates : [],
|
|
346
|
+
},
|
|
347
|
+
properties: {
|
|
348
|
+
id: relation.id,
|
|
349
|
+
type: "relation",
|
|
350
|
+
...relation.info,
|
|
351
|
+
...relation.tags,
|
|
352
|
+
},
|
|
353
|
+
};
|
|
354
|
+
}
|
|
364
355
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
356
|
+
// No geometry available
|
|
357
|
+
return {
|
|
358
|
+
type: "Feature",
|
|
359
|
+
id: relation.id,
|
|
360
|
+
geometry: {
|
|
361
|
+
type: "GeometryCollection",
|
|
362
|
+
geometries: [],
|
|
363
|
+
},
|
|
364
|
+
properties: {
|
|
365
|
+
id: relation.id,
|
|
366
|
+
type: "relation",
|
|
367
|
+
...relation.info,
|
|
368
|
+
...relation.tags,
|
|
369
|
+
},
|
|
370
|
+
};
|
|
380
371
|
}
|
|
381
372
|
|
|
382
373
|
/**
|
|
@@ -399,29 +390,33 @@ export function relationToFeature(
|
|
|
399
390
|
* ```
|
|
400
391
|
*/
|
|
401
392
|
export function osmEntityToGeoJSONFeature(
|
|
402
|
-
|
|
403
|
-
|
|
393
|
+
osm: OsmReader,
|
|
394
|
+
entity: OsmEntity,
|
|
404
395
|
): OsmGeoJSONFeature<
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
396
|
+
| GeoJSON.Point
|
|
397
|
+
| GeoJSON.LineString
|
|
398
|
+
| GeoJSON.Polygon
|
|
399
|
+
| GeoJSON.MultiPolygon
|
|
400
|
+
| GeoJSON.MultiLineString
|
|
401
|
+
| GeoJSON.MultiPoint
|
|
402
|
+
| GeoJSON.GeometryCollection
|
|
412
403
|
> {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
404
|
+
if (isNode(entity)) {
|
|
405
|
+
return nodeToFeature(entity);
|
|
406
|
+
}
|
|
407
|
+
if (isWay(entity)) {
|
|
408
|
+
return wayToFeature(entity, (ref) => {
|
|
409
|
+
const coordinate = osm.nodes.getNodeLonLat({ id: ref });
|
|
410
|
+
if (!coordinate) throw Error(`Node ${ref} not found for way geometry`);
|
|
411
|
+
return coordinate;
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
if (isRelation(entity)) {
|
|
415
|
+
return relationToFeature(
|
|
416
|
+
entity,
|
|
417
|
+
(ref) => osm.nodes.getNodeLonLat({ id: ref }) ?? undefined,
|
|
418
|
+
(ref) => osm.ways.getById(ref),
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
throw new Error("Unknown entity type");
|
|
427
422
|
}
|