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/Makefile +1 -1
- package/index.html +7 -3
- package/lib/index.d.ts +21 -0
- package/lib/index.js +51 -59
- package/lib/osmobjs.js +1 -1
- package/lib/xmlparser.js +1 -1
- package/osm2geojson-lite +10 -0
- package/package.json +12 -2
- package/ts/release/index.js +195 -0
- package/ts/release/osmobjs.js +348 -0
- package/ts/release/utils.js +213 -0
- package/ts/release/xmlparser.js +157 -0
- package/ts/src/index.d.ts +17 -0
- package/ts/src/index.ts +217 -169
- package/ts/src/osmobjs.ts +400 -365
- package/ts/src/typings.d.ts +1 -1
- package/ts/src/utils.ts +207 -170
- package/ts/src/xmlparser.ts +173 -132
- package/ts/tsconfig.json +4 -0
- package/ts/tslint.json +24 -0
- package/ts/types/imports.d.ts +1 -0
package/ts/src/osmobjs.ts
CHANGED
|
@@ -1,378 +1,413 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
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
|
+
}
|