osm2geojson-lite 0.8.13 → 0.9.0

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/ts/src/osmobjs.ts CHANGED
@@ -1,378 +1,413 @@
1
- import {first, last, coordsToKey,
2
- addToMap, removeFromMap, getFirstFromMap,
3
- isRing, ringDirection, ptInsidePolygon, strToFloat,
4
- LateBinder, WayCollection, RefElements} from './utils';
1
+ import {Feature, GeometryObject, LineString,
2
+ MultiLineString, MultiPoint, MultiPolygon,
3
+ Point, Polygon} from 'geojson';
4
+
5
+ import {first, isRing, last, ptInsidePolygon, ringDirection, strToFloat} from './utils';
6
+ import {LateBinder, RefElements, WayCollection} from './utils';
5
7
 
6
8
  import polygonTags from './polytags.json';
7
9
 
8
10
  class OsmObject {
9
- type: string;
10
- id: string;
11
- refElems: RefElements;
12
- tags: object;
13
- props: object;
14
- refCount: number;
15
- hasTag: boolean;
16
-
17
- constructor(type: string, id: string, refElems: RefElements) {
18
- this.type = type;
19
- this.id = id;
20
- this.refElems = refElems;
21
- this.tags = {};
22
- this.props = {id: this.getCompositeId()};
23
- this.refCount = 0;
24
- this.hasTag = false;
25
- if (refElems) refElems.add(this.getCompositeId(), this);
26
- }
27
-
28
- addTags(tags) {
29
- this.tags = Object.assign(this.tags, tags);
30
- this.hasTag = tags? true : false;
31
- }
32
-
33
- addTag(k, v) {
34
- this.tags[k] = v;
35
- this.hasTag = k? true : false;
36
- }
37
-
38
- addProp(k, v) {
39
- this.props[k] = v;
40
- }
41
-
42
- addProps(props) {
43
- this.props = Object.assign(this.props, props);
44
- }
45
-
46
- getCompositeId(): string {
47
- return `${this.type}/${this.id}`;
48
- }
49
-
50
- getProps(): Object {
51
- return Object.assign(this.props, this.tags);
52
- }
53
-
54
- toFeatureArray(): any[] {
55
- return [];
56
- }
11
+ public refCount: number;
12
+
13
+ protected refElems: RefElements;
14
+
15
+ private type: string;
16
+ private id: string;
17
+ private tags: {[k: string]: string};
18
+ private props: {[k: string]: string};
19
+ private hasTag: boolean;
20
+
21
+ constructor(type: string, id: string, refElems: RefElements) {
22
+ this.type = type;
23
+ this.id = id;
24
+ this.refElems = refElems;
25
+ this.tags = {};
26
+ this.props = {id: this.getCompositeId()};
27
+ this.refCount = 0;
28
+ this.hasTag = false;
29
+ if (refElems) {
30
+ refElems.add(this.getCompositeId(), this);
31
+ }
32
+ }
33
+
34
+ public addTags(tags: {[k: string]: string}) {
35
+ this.tags = Object.assign(this.tags, tags);
36
+ this.hasTag = tags ? true : false;
37
+ }
38
+
39
+ public addTag(k: string, v: string) {
40
+ this.tags[k] = v;
41
+ this.hasTag = k ? true : false;
42
+ }
43
+
44
+ public addProp(k: string, v: any) {
45
+ this.props[k] = v;
46
+ }
47
+
48
+ public addProps(props: {[k: string]: string}) {
49
+ this.props = Object.assign(this.props, props);
50
+ }
51
+
52
+ public getCompositeId(): string {
53
+ return `${this.type}/${this.id}`;
54
+ }
55
+
56
+ public getProps(): {[k: string]: string} {
57
+ return Object.assign(this.props, this.tags);
58
+ }
59
+
60
+ public toFeatureArray(): Array<Feature<any, any>> {
61
+ return [];
62
+ }
57
63
  }
58
64
 
59
65
  export class Node extends OsmObject {
60
- latLng: any;
61
-
62
- constructor(id: string, refElems: RefElements) {
63
- super('node', id, refElems);
64
- this.latLng = null;
65
- }
66
-
67
- setLatLng(latLng) {
68
- this.latLng = latLng;
69
- }
70
-
71
- toFeatureArray(): any[] {
72
- if (this.latLng)
73
- return [{
74
- type: 'Feature',
75
- id: this.getCompositeId(),
76
- properties: this.getProps(),
77
- geometry: {
78
- type: 'Point',
79
- coordinates: strToFloat([this.latLng.lon, this.latLng.lat])
80
- }
81
- }];
82
-
83
- return [];
84
- }
85
-
86
- getLatLng(): any {
87
- return this.latLng;
88
- }
66
+ private latLng: {lon: string, lat: string} | null;
67
+
68
+ constructor(id: string, refElems: RefElements) {
69
+ super('node', id, refElems);
70
+ this.latLng = null;
71
+ }
72
+
73
+ public setLatLng(latLng: {lat: string, lon: string}) {
74
+ this.latLng = latLng;
75
+ }
76
+
77
+ public toFeatureArray(): Array<Feature<any, any>> {
78
+ if (this.latLng) {
79
+ return [{
80
+ type: 'Feature',
81
+ id: this.getCompositeId(),
82
+ properties: this.getProps(),
83
+ geometry: {
84
+ type: 'Point',
85
+ coordinates: strToFloat([this.latLng.lon, this.latLng.lat]),
86
+ },
87
+ }];
88
+ }
89
+ return [];
90
+ }
91
+
92
+ public getLatLng(): {lat: string, lon: string} | null {
93
+ return this.latLng;
94
+ }
89
95
  }
90
96
 
91
97
  export class Way extends OsmObject {
92
- latLngArray: any[];
93
- isPolygon: boolean;
94
-
95
- constructor(id: string, refElems: RefElements) {
96
- super('way', id, refElems);
97
- this.latLngArray = [];
98
- this.isPolygon = false;
99
- }
100
-
101
- addLatLng(latLng: any) {
102
- this.latLngArray.push(latLng);
103
- }
104
-
105
- setLatLngArray(latLngArray: any[]) {
106
- this.latLngArray = latLngArray;
107
- }
108
-
109
- addNodeRef(ref: string) {
110
- let binder = new LateBinder(this.latLngArray, function(id) {
111
- let node = this.refElems.get(`node/${id}`);
112
- if (node) {
113
- node.refCount++;
114
- return node.getLatLng();
115
- }
116
- }, this, [ref]);
117
-
118
- this.latLngArray.push(binder);
119
- this.refElems.addBinder(binder);
120
- }
121
-
122
- analyzeTag(k: string, v: string) {
123
- let o = (<any>polygonTags)[k];
124
- if (o) {
125
- this.isPolygon = true;
126
- if (o.whitelist) this.isPolygon = o.whitelist.indexOf(v) >= 0? true : false;
127
- else if(o.blacklist) this.isPolygon = o.blacklist.indexOf(v) >= 0? false : true;
128
- }
129
- }
130
-
131
- addTags(tags: object) {
132
- super.addTags(tags);
133
- for (let [k, v] of Object.entries(tags))
134
- this.analyzeTag(k, v);
135
- }
136
-
137
- addTag(k: string, v: string) {
138
- super.addTag(k, v);
139
- this.analyzeTag(k, v);
140
- }
141
-
142
- toCoordsArray(): any[] {
143
- return this.latLngArray.map(latLng => [latLng.lon, latLng.lat]);
144
- }
145
-
146
- toFeatureArray(): any[] {
147
- let coordsArray = this.toCoordsArray();
148
- if (coordsArray.length > 1) {
149
- coordsArray = strToFloat(coordsArray);
150
- let feature = {
151
- type: 'Feature',
152
- id: this.getCompositeId(),
153
- properties: this.getProps(),
154
- geometry: {
155
- type: 'LineString',
156
- coordinates: coordsArray
157
- }
158
- };
159
-
160
- if (this.isPolygon && isRing(coordsArray)) {
161
- if (ringDirection(coordsArray) !== 'counterclockwise') coordsArray.reverse();
162
-
163
- feature.geometry = {
164
- type: 'Polygon',
165
- coordinates: [coordsArray]
166
- };
167
-
168
- return [feature];
169
- }
170
-
171
- return [feature];
172
- }
173
-
174
- return [];
175
- }
98
+ private latLngArray: Array<{lon: string, lat: string} | LateBinder>;
99
+ private isPolygon: boolean;
100
+
101
+ constructor(id: string, refElems: RefElements) {
102
+ super('way', id, refElems);
103
+ this.latLngArray = [];
104
+ this.isPolygon = false;
105
+ }
106
+
107
+ public addLatLng(latLng: {lat: string, lon: string}) {
108
+ this.latLngArray.push(latLng);
109
+ }
110
+
111
+ public setLatLngArray(latLngArray: Array<{lat: string, lon: string, [k: string]: any}>) {
112
+ this.latLngArray = latLngArray;
113
+ }
114
+
115
+ public addNodeRef(ref: string) {
116
+ const binder = new LateBinder(this.latLngArray, function(id: string) {
117
+ const node = this.refElems.get(`node/${id}`);
118
+ if (node) {
119
+ node.refCount++;
120
+ return node.getLatLng();
121
+ }
122
+ }, this, [ref]);
123
+
124
+ this.latLngArray.push(binder);
125
+ this.refElems.addBinder(binder);
126
+ }
127
+
128
+ public addTags(tags: {[k: string]: string}) {
129
+ super.addTags(tags);
130
+ for (const [k, v] of Object.entries(tags)) {
131
+ this.analyzeTag(k, v);
132
+ }
133
+ }
134
+
135
+ public addTag(k: string, v: string) {
136
+ super.addTag(k, v);
137
+ this.analyzeTag(k, v);
138
+ }
139
+
140
+ public toCoordsArray(): string[][] {
141
+ return (this.latLngArray as Array<{lon: string, lat: string}>).map((latLng) => [latLng.lon, latLng.lat]);
142
+ }
143
+
144
+ public toFeatureArray(): Array<Feature<any, any>> {
145
+ let coordsArray: any[] = this.toCoordsArray();
146
+ if (coordsArray.length > 1) {
147
+ coordsArray = strToFloat(coordsArray);
148
+ const feature: Feature<any, any> = {
149
+ type: 'Feature',
150
+ id: this.getCompositeId(),
151
+ properties: this.getProps(),
152
+ geometry: {
153
+ type: 'LineString',
154
+ coordinates: coordsArray,
155
+ },
156
+ };
157
+
158
+ if (this.isPolygon && isRing(coordsArray)) {
159
+ if (ringDirection(coordsArray) !== 'counterclockwise') {
160
+ coordsArray.reverse();
161
+ }
162
+
163
+ feature.geometry = {
164
+ type: 'Polygon',
165
+ coordinates: [coordsArray],
166
+ };
167
+
168
+ return [feature];
169
+ }
170
+
171
+ return [feature];
172
+ }
173
+
174
+ return [];
175
+ }
176
+
177
+ private analyzeTag(k: string, v: string) {
178
+ const o = (polygonTags as {k: string, v: any})[k];
179
+ if (o) {
180
+ this.isPolygon = true;
181
+ if (o.whitelist) {
182
+ this.isPolygon = o.whitelist.indexOf(v) >= 0 ? true : false;
183
+ } else if (o.blacklist) {
184
+ this.isPolygon = o.blacklist.indexOf(v) >= 0 ? false : true;
185
+ }
186
+ }
187
+ }
176
188
  }
177
189
 
178
190
  export class Relation extends OsmObject {
179
- relations: any[];
180
- nodes: any[];
181
- bounds: any[];
182
- [k: string]: any;
183
-
184
- constructor(id: string, refElems: RefElements) {
185
- super('relation', id, refElems);
186
- this.relations = [];
187
- this.nodes = [];
188
- this.bounds = <any>null;
189
- }
190
-
191
- setBounds(bounds) {
192
- this.bounds = bounds;
193
- }
194
-
195
- addMember(member) {
196
- switch (member.type) {
197
- // super relation, need to do combination
198
- case 'relation':
199
- let binder = new LateBinder(this.relations, function(id) {
200
- let relation = this.refElems.get(`relation/${id}`);
201
- if (relation) {
202
- relation.refCount++;
203
- return relation;
204
- }
205
- }, this, [member.ref]);
206
- this.relations.push(binder);
207
- this.refElems.addBinder(binder);
208
- break;
209
-
210
- case 'way':
211
- if (!member.role) member.role === '';
212
- let ways = this[member.role];
213
- if (!ways) ways = this[member.role] = [];
214
- if (member.geometry) {
215
- let way = new Way(member.ref, this.refElems);
216
- way.setLatLngArray(member.geometry);
217
- way.refCount++;
218
- ways.push(way);
219
- } else if (member.nodes) {
220
- let way = new Way(member.ref, this.refElems);
221
- for (let nid of member.nodes) {
222
- way.addNodeRef(nid);
223
- }
224
- way.refCount++;
225
- ways.push(way);
226
- } else {
227
- let binder = new LateBinder(ways, function(id) {
228
- let way = this.refElems.get(`way/${id}`);
229
- if (way) {
230
- way.refCount++;
231
- return way;
232
- }
233
- }, this, [member.ref]);
234
- ways.push(binder);
235
- this.refElems.addBinder(binder);
236
- }
237
- break;
238
-
239
- case 'node':
240
- let node = <any>null;
241
- if (member.lat && member.lon) {
242
- node = new Node(member.ref, this.refElems);
243
- node.setLatLng({lon: member.lon, lat: member.lat});
244
- if (member.tags) node.addTags(member.tags);
245
- for (let [k, v] of Object.entries(member))
246
- if (['id', 'type', 'lat', 'lon'].indexOf(k) < 0)
247
- node.addProp(k, v);
248
-
249
- node.refCount++;
250
- this.nodes.push(node);
251
- } else {
252
- let binder = new LateBinder(this.nodes, function(id) {
253
- let node = this.refElems.get(`node/${id}`);
254
- if (node) {
255
- node.refCount++;
256
- return node;
257
- }
258
- }, this, [member.ref]);
259
- this.nodes.push(binder);
260
- this.refElems.addBinder(binder);
261
- }
262
- break;
263
-
264
- default:
265
- break;
266
- }
267
- }
268
-
269
- toFeatureArray() {
270
- const constructStringGeometry = (ws) => {
271
- let strings = ws? ws.toStrings() : [];
272
- if (strings.length > 0) {
273
- if (strings.length === 1) return {
274
- type: 'LineString',
275
- coordinates: strings[0]
276
- }
277
-
278
- return {
279
- type: 'MultiLineString',
280
- coordinates: strings
281
- }
282
- }
283
- return null; }
284
-
285
- const constructPolygonGeometry = (ows, iws) => {
286
- let outerRings = ows? ows.toRings('counterclockwise') : [],
287
- innerRings = iws? iws.toRings('clockwise') : [];
288
-
289
- if (outerRings.length > 0) {
290
- let compositPolyons: any[] = [];
291
-
292
- let ring = null;
293
- for (ring of outerRings)
294
- compositPolyons.push([ring]);
295
-
296
- // link inner polygons to outer containers
297
- while (ring = innerRings.shift()) {
298
- for (let idx in outerRings) {
299
- if (ptInsidePolygon(first(ring), outerRings[idx])) {
300
- compositPolyons[idx].push(ring);
301
- break;
302
- }
303
- }
304
- }
305
-
306
- // construct the Polygon/MultiPolygon geometry
307
- if (compositPolyons.length === 1) return {
308
- type: 'Polygon',
309
- coordinates: compositPolyons[0]
310
- };
311
-
312
- return {
313
- type: 'MultiPolygon',
314
- coordinates: compositPolyons
315
- }
316
- }
317
-
318
- return null;
319
- }
320
-
321
- let polygonFeatures: any[] = [], stringFeatures: any[] = [], pointFeatures: any[] = [];
322
- const waysFieldNames = ['outer', 'inner', ''];
323
- // need to do combination when there're nested relations
324
- for (let relation of this.relations) {
325
- if (relation) {
326
- for (let fieldName of waysFieldNames) {
327
- let ways = relation[fieldName];
328
- if (ways) {
329
- let thisWays = this[fieldName];
330
- if (thisWays) [].splice.apply(thisWays, [thisWays.length, 0].concat(ways));
331
- else this[fieldName] = ways;
332
- }
333
- }
334
- }
335
- }
336
-
337
- for (let fieldName of waysFieldNames) {
338
- let ways = this[fieldName];
339
- if (ways) {
340
- this[fieldName] = new WayCollection();
341
- for (let way of ways)
342
- this[fieldName].addWay(way);
343
- }
344
- }
345
-
346
- let geometry: any = null;
347
-
348
- let feature: {[k: string]: any} = {
349
- type: 'Feature',
350
- id: this.getCompositeId(),
351
- bbox: this.bounds,
352
- properties: this.getProps()
353
- };
354
-
355
- if (!this.bounds)
356
- delete feature.bbox;
357
-
358
- if (this.outer) {
359
- geometry = constructPolygonGeometry(this.outer, this.inner);
360
- if (geometry){
361
- feature.geometry = geometry;
362
- polygonFeatures.push(feature);
363
- }
364
- }
365
- else if (this['']) {
366
- geometry = constructStringGeometry(this['']);
367
- if (geometry) {
368
- feature.geometry = geometry;
369
- stringFeatures.push(feature);
370
- }
371
- }
372
-
373
- for (let node of this.nodes)
374
- pointFeatures = pointFeatures.concat(node.toFeatureArray());
375
-
376
- return polygonFeatures.concat(stringFeatures).concat(pointFeatures);
377
- }
378
- }
191
+ private relations: any[];
192
+ private nodes: any[];
193
+ private bounds: number[] | undefined;
194
+
195
+ [k: string]: any;
196
+
197
+ constructor(id: string, refElems: RefElements) {
198
+ super('relation', id, refElems);
199
+ this.relations = [];
200
+ this.nodes = [];
201
+ this.bounds = undefined;
202
+ }
203
+
204
+ public setBounds(bounds: any[]) {
205
+ this.bounds = bounds;
206
+ }
207
+
208
+ public addMember(member: {[k: string]: any}) {
209
+ switch (member.type) {
210
+ // super relation, need to do combination
211
+ case 'relation':
212
+ let binder = new LateBinder(this.relations, function(id) {
213
+ const relation = this.refElems.get(`relation/${id}`);
214
+ if (relation) {
215
+ relation.refCount++;
216
+ return relation;
217
+ }
218
+ }, this, [member.ref]);
219
+ this.relations.push(binder);
220
+ this.refElems.addBinder(binder);
221
+ break;
222
+
223
+ case 'way':
224
+ if (!member.role) {
225
+ member.role = '';
226
+ }
227
+ let ways = this[member.role];
228
+ if (!ways) {
229
+ ways = this[member.role] = [];
230
+ }
231
+ if (member.geometry) {
232
+ const way = new Way(member.ref, this.refElems);
233
+ way.setLatLngArray(member.geometry);
234
+ way.refCount++;
235
+ ways.push(way);
236
+ } else if (member.nodes) {
237
+ const way = new Way(member.ref, this.refElems);
238
+ for (const nid of member.nodes) {
239
+ way.addNodeRef(nid);
240
+ }
241
+ way.refCount++;
242
+ ways.push(way);
243
+ } else {
244
+ binder = new LateBinder(ways, function(nid) {
245
+ const way = this.refElems.get(`way/${nid}`);
246
+ if (way) {
247
+ way.refCount++;
248
+ return way;
249
+ }
250
+ }, this, [member.ref]);
251
+ ways.push(binder);
252
+ this.refElems.addBinder(binder);
253
+ }
254
+ break;
255
+
256
+ case 'node':
257
+ let node: Node | null = null;
258
+ if (member.lat && member.lon) {
259
+ node = new Node(member.ref, this.refElems);
260
+ node.setLatLng({lon: member.lon, lat: member.lat});
261
+ if (member.tags) {
262
+ node.addTags(member.tags);
263
+ }
264
+ for (const [k, v] of Object.entries(member)) {
265
+ if (['id', 'type', 'lat', 'lon'].indexOf(k) < 0) {
266
+ node.addProp(k, v);
267
+ }
268
+ }
269
+
270
+ node.refCount++;
271
+ this.nodes.push(node);
272
+ } else {
273
+ binder = new LateBinder(this.nodes, function(id) {
274
+ const nn = this.refElems.get(`node/${id}`);
275
+ if (nn) {
276
+ nn.refCount++;
277
+ return nn;
278
+ }
279
+ }, this, [member.ref]);
280
+ this.nodes.push(binder);
281
+ this.refElems.addBinder(binder);
282
+ }
283
+ default:
284
+ break;
285
+ }
286
+ }
287
+
288
+ public toFeatureArray(): Array<Feature<any, any>> {
289
+ function constructStringGeometry(ws: WayCollection): LineString | MultiLineString | null {
290
+ const strings = ws ? ws.toStrings() : [];
291
+ if (strings.length > 0) {
292
+ if (strings.length === 1) {
293
+ return {
294
+ type: 'LineString',
295
+ coordinates: strings[0],
296
+ };
297
+ }
298
+
299
+ return {
300
+ type: 'MultiLineString',
301
+ coordinates: strings,
302
+ };
303
+ }
304
+ return null;
305
+ }
306
+
307
+ function constructPolygonGeometry(ows: WayCollection, iws: WayCollection): Polygon | MultiPolygon | null {
308
+ const outerRings = ows ? ows.toRings('counterclockwise') : [];
309
+ const innerRings = iws ? iws.toRings('clockwise') : [];
310
+
311
+ if (outerRings.length > 0) {
312
+ const compositPolyons: any[] = [];
313
+
314
+ let ring: number[][] | undefined;
315
+ for (ring of outerRings) {
316
+ compositPolyons.push([ring]);
317
+ }
318
+
319
+ // link inner polygons to outer containers
320
+ ring = innerRings.shift();
321
+ while (ring) {
322
+ for (const idx in outerRings) {
323
+ if (ptInsidePolygon(first(ring), outerRings[idx])) {
324
+ compositPolyons[idx].push(ring);
325
+ break;
326
+ }
327
+ }
328
+ ring = innerRings.shift();
329
+ }
330
+
331
+ // construct the Polygon/MultiPolygon geometry
332
+ if (compositPolyons.length === 1) {
333
+ return {
334
+ type: 'Polygon',
335
+ coordinates: compositPolyons[0],
336
+ };
337
+ }
338
+
339
+ return {
340
+ type: 'MultiPolygon',
341
+ coordinates: compositPolyons,
342
+ };
343
+ }
344
+
345
+ return null;
346
+ }
347
+
348
+ const polygonFeatures: Array<Feature<Polygon | MultiPolygon, any>> = [];
349
+ const stringFeatures: Array<Feature<LineString | MultiLineString, any>> = [];
350
+ let pointFeatures: Array<Feature<Point | MultiPoint, any>> = [];
351
+ const waysFieldNames = ['outer', 'inner', ''];
352
+ // need to do combination when there're nested relations
353
+ for (const relation of this.relations) {
354
+ if (relation) {
355
+ for (const fieldName of waysFieldNames) {
356
+ const ways = relation[fieldName];
357
+ if (ways) {
358
+ const thisWays = this[fieldName];
359
+ if (thisWays) {
360
+ [].splice.apply(thisWays, [thisWays.length, 0].concat(ways));
361
+ } else {
362
+ this[fieldName] = ways;
363
+ }
364
+ }
365
+ }
366
+ }
367
+ }
368
+
369
+ for (const fieldName of waysFieldNames) {
370
+ const ways = this[fieldName];
371
+ if (ways) {
372
+ this[fieldName] = new WayCollection();
373
+ for (const way of ways) {
374
+ this[fieldName].addWay(way);
375
+ }
376
+ }
377
+ }
378
+
379
+ let geometry: GeometryObject | null = null;
380
+
381
+ const feature: Feature<any, any> = {
382
+ type: 'Feature',
383
+ id: this.getCompositeId(),
384
+ bbox: this.bounds,
385
+ properties: this.getProps(),
386
+ geometry: null,
387
+ };
388
+
389
+ if (!this.bounds) {
390
+ delete feature.bbox;
391
+ }
392
+
393
+ if (this.outer) {
394
+ geometry = constructPolygonGeometry(this.outer, this.inner);
395
+ if (geometry) {
396
+ feature.geometry = geometry;
397
+ polygonFeatures.push(feature as Feature<Polygon | MultiPolygon, any>);
398
+ }
399
+ } else if (this['']) {
400
+ geometry = constructStringGeometry(this['']);
401
+ if (geometry) {
402
+ feature.geometry = geometry;
403
+ stringFeatures.push(feature as Feature<LineString | MultiLineString, any>);
404
+ }
405
+ }
406
+
407
+ for (const node of this.nodes) {
408
+ pointFeatures = pointFeatures.concat(node.toFeatureArray());
409
+ }
410
+
411
+ return [...polygonFeatures, ...stringFeatures, ...pointFeatures];
412
+ }
413
+ }