osm2geojson-lite 1.1.0 → 1.1.2
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/dist/node/index.d.ts +25 -0
- package/dist/node/index.js +196 -0
- package/dist/node/late-binder.d.ts +8 -0
- package/dist/node/late-binder.js +24 -0
- package/dist/node/node.d.ts +14 -0
- package/dist/node/node.js +31 -0
- package/dist/node/osm-object.d.ts +25 -0
- package/dist/node/osm-object.js +38 -0
- package/dist/node/polytags.json +84 -0
- package/dist/node/ref-elements.d.ts +9 -0
- package/dist/node/ref-elements.js +19 -0
- package/dist/node/relation.d.ts +20 -0
- package/dist/node/relation.js +205 -0
- package/dist/node/utils.d.ts +22 -0
- package/dist/node/utils.js +97 -0
- package/dist/node/way-collection.d.ts +14 -0
- package/dist/node/way-collection.js +108 -0
- package/dist/node/way.d.ts +21 -0
- package/dist/node/way.js +87 -0
- package/dist/node/xmlparser.d.ts +32 -0
- package/dist/node/xmlparser.js +161 -0
- package/dist/web/osm2geojson-lite.js +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { FeatureCollection, GeometryObject } from 'geojson';
|
|
2
|
+
interface IOptions {
|
|
3
|
+
/**
|
|
4
|
+
* When it's set to `true`, the returned geojson will include all elements that meet the specified conditions in `FeatureCollection` format;
|
|
5
|
+
* otherwise, only the bare geometry of the first `relation` element will be returned.
|
|
6
|
+
* @default false
|
|
7
|
+
*/
|
|
8
|
+
completeFeature?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* When it's set to `true`, the returned geojson will include all elements with tags (i.e., tagged)
|
|
11
|
+
* until `suppressWay` changes its behavior a bit; otherwise only the unreferenced ones get returned.
|
|
12
|
+
* @default false
|
|
13
|
+
*/
|
|
14
|
+
renderTagged?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* When it's set to `true`, the returned `FeatureCollection` will exclude all referenced `way`s even though they are tagged;
|
|
17
|
+
* otherwise the features of those `way`s will be included in the resulted result as well.
|
|
18
|
+
* @default true
|
|
19
|
+
*/
|
|
20
|
+
excludeWay?: boolean;
|
|
21
|
+
}
|
|
22
|
+
declare function osm2geojson(osm: string | {
|
|
23
|
+
[k: string]: any;
|
|
24
|
+
}, opts?: IOptions): FeatureCollection<GeometryObject>;
|
|
25
|
+
export = osm2geojson;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const utils_1 = require("./utils");
|
|
3
|
+
const xmlparser_1 = require("./xmlparser");
|
|
4
|
+
const node_1 = require("./node");
|
|
5
|
+
const way_1 = require("./way");
|
|
6
|
+
const relation_1 = require("./relation");
|
|
7
|
+
const ref_elements_1 = require("./ref-elements");
|
|
8
|
+
function parseOptions(options) {
|
|
9
|
+
if (!options) {
|
|
10
|
+
return { completeFeature: false, renderTagged: false, excludeWay: true };
|
|
11
|
+
}
|
|
12
|
+
let excludeWay = options.excludeWay === undefined || options.excludeWay;
|
|
13
|
+
let completeFeature = options.completeFeature ? true : false;
|
|
14
|
+
let renderTagged = options.renderTagged ? true : false;
|
|
15
|
+
return { completeFeature, renderTagged, excludeWay };
|
|
16
|
+
}
|
|
17
|
+
function detectFormat(o) {
|
|
18
|
+
if (o.elements) {
|
|
19
|
+
return 'json';
|
|
20
|
+
}
|
|
21
|
+
if (o.indexOf('<osm') >= 0) {
|
|
22
|
+
return 'xml';
|
|
23
|
+
}
|
|
24
|
+
if (o.trim().startsWith('{')) {
|
|
25
|
+
return 'json-raw';
|
|
26
|
+
}
|
|
27
|
+
return 'invalid';
|
|
28
|
+
}
|
|
29
|
+
;
|
|
30
|
+
function analyzeFeaturesFromJson(osm, refElements) {
|
|
31
|
+
for (const elem of osm.elements) {
|
|
32
|
+
switch (elem.type) {
|
|
33
|
+
case 'node':
|
|
34
|
+
const node = new node_1.Node(elem.id, refElements);
|
|
35
|
+
if (elem.tags) {
|
|
36
|
+
node.addTags(elem.tags);
|
|
37
|
+
}
|
|
38
|
+
node.addProps((0, utils_1.purgeProps)(elem, ['id', 'type', 'tags', 'lat', 'lon']));
|
|
39
|
+
node.setLatLng(elem);
|
|
40
|
+
break;
|
|
41
|
+
case 'way':
|
|
42
|
+
const way = new way_1.Way(elem.id, refElements);
|
|
43
|
+
if (elem.tags) {
|
|
44
|
+
way.addTags(elem.tags);
|
|
45
|
+
}
|
|
46
|
+
way.addProps((0, utils_1.purgeProps)(elem, ['id', 'type', 'tags', 'nodes', 'geometry']));
|
|
47
|
+
if (elem.geometry) {
|
|
48
|
+
way.setLatLngArray(elem.geometry);
|
|
49
|
+
}
|
|
50
|
+
else if (elem.nodes) {
|
|
51
|
+
for (const n of elem.nodes) {
|
|
52
|
+
way.addNodeRef(n);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
break;
|
|
56
|
+
case 'relation':
|
|
57
|
+
const relation = new relation_1.Relation(elem.id, refElements);
|
|
58
|
+
if (elem.bounds) {
|
|
59
|
+
relation.setBounds([parseFloat(elem.bounds.minlon), parseFloat(elem.bounds.minlat), parseFloat(elem.bounds.maxlon), parseFloat(elem.bounds.maxlat)]);
|
|
60
|
+
}
|
|
61
|
+
if (elem.tags) {
|
|
62
|
+
relation.addTags(elem.tags);
|
|
63
|
+
}
|
|
64
|
+
relation.addProps((0, utils_1.purgeProps)(elem, ['id', 'type', 'tags', 'bounds', 'members']));
|
|
65
|
+
if (elem.members) {
|
|
66
|
+
for (const member of elem.members) {
|
|
67
|
+
relation.addMember(member);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
default:
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function analyzeFeaturesFromXml(osm, refElements) {
|
|
76
|
+
const xmlParser = new xmlparser_1.XmlParser({ progressive: true });
|
|
77
|
+
xmlParser.on('</osm.node>', (node) => {
|
|
78
|
+
const nd = new node_1.Node(node.id, refElements);
|
|
79
|
+
for (const [k, v] of Object.entries(node)) {
|
|
80
|
+
if (!k.startsWith('$') && ['id', 'lon', 'lat'].indexOf(k) < 0) {
|
|
81
|
+
nd.addProp(k, v);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
nd.setLatLng(node);
|
|
85
|
+
if (node.$innerNodes) {
|
|
86
|
+
for (const ind of node.$innerNodes) {
|
|
87
|
+
if (ind.$tag === 'tag') {
|
|
88
|
+
nd.addTag(ind.k, ind.v);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
xmlParser.on('</osm.way>', (node) => {
|
|
94
|
+
const way = new way_1.Way(node.id, refElements);
|
|
95
|
+
for (const [k, v] of Object.entries(node)) {
|
|
96
|
+
if (!k.startsWith('$') && ['id'].indexOf(k) < 0) {
|
|
97
|
+
way.addProp(k, v);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (node.$innerNodes) {
|
|
101
|
+
for (const ind of node.$innerNodes) {
|
|
102
|
+
if (ind.$tag === 'nd') {
|
|
103
|
+
if (ind.lon && ind.lat) {
|
|
104
|
+
way.addLatLng(ind);
|
|
105
|
+
}
|
|
106
|
+
else if (ind.ref) {
|
|
107
|
+
way.addNodeRef(ind.ref);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else if (ind.$tag === 'tag') {
|
|
111
|
+
way.addTag(ind.k, ind.v);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
xmlParser.on('<osm.relation>', (node) => new relation_1.Relation(node.id, refElements));
|
|
117
|
+
xmlParser.on('</osm.relation.member>', (node, parent) => {
|
|
118
|
+
const relation = refElements.get(`relation/${parent === null || parent === void 0 ? void 0 : parent.id}`);
|
|
119
|
+
const member = {
|
|
120
|
+
type: node.type,
|
|
121
|
+
role: node.role ? node.role : '',
|
|
122
|
+
ref: node.ref,
|
|
123
|
+
};
|
|
124
|
+
if (node.lat && node.lon) {
|
|
125
|
+
member.lat = node.lat, member.lon = node.lon, member.tags = {};
|
|
126
|
+
for (const [k, v] of Object.entries(node)) {
|
|
127
|
+
if (!k.startsWith('$') && ['type', 'lat', 'lon'].indexOf(k) < 0) {
|
|
128
|
+
member[k] = v;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (node.$innerNodes) {
|
|
133
|
+
const geometry = [];
|
|
134
|
+
const nodes = [];
|
|
135
|
+
for (const ind of node.$innerNodes) {
|
|
136
|
+
if (ind.lat && ind.lon) {
|
|
137
|
+
geometry.push(ind);
|
|
138
|
+
}
|
|
139
|
+
else if (ind.ref) {
|
|
140
|
+
nodes.push(ind.ref);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (geometry.length > 0) {
|
|
144
|
+
member.geometry = geometry;
|
|
145
|
+
}
|
|
146
|
+
else if (nodes.length > 0) {
|
|
147
|
+
member.nodes = nodes;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
relation.addMember(member);
|
|
151
|
+
});
|
|
152
|
+
xmlParser.on('</osm.relation.bounds>', (node, parent) => {
|
|
153
|
+
refElements.get(`relation/${parent === null || parent === void 0 ? void 0 : parent.id}`).setBounds([parseFloat(node.minlon), parseFloat(node.minlat), parseFloat(node.maxlon), parseFloat(node.maxlat)]);
|
|
154
|
+
});
|
|
155
|
+
xmlParser.on('</osm.relation.tag>', (node, parent) => {
|
|
156
|
+
refElements.get(`relation/${parent === null || parent === void 0 ? void 0 : parent.id}`).addTag(node.k, node.v);
|
|
157
|
+
});
|
|
158
|
+
xmlParser.parse(osm);
|
|
159
|
+
}
|
|
160
|
+
;
|
|
161
|
+
function osm2geojson(osm, opts) {
|
|
162
|
+
let { completeFeature, renderTagged, excludeWay } = parseOptions(opts);
|
|
163
|
+
let format = detectFormat(osm);
|
|
164
|
+
const refElements = new ref_elements_1.RefElements();
|
|
165
|
+
let featureArray = [];
|
|
166
|
+
if (format === 'json-raw') {
|
|
167
|
+
osm = JSON.parse(osm);
|
|
168
|
+
if (osm.elements) {
|
|
169
|
+
format = 'json';
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
format = 'invalid';
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (format === 'json') {
|
|
176
|
+
analyzeFeaturesFromJson(osm, refElements);
|
|
177
|
+
}
|
|
178
|
+
else if (format === 'xml') {
|
|
179
|
+
analyzeFeaturesFromXml(osm, refElements);
|
|
180
|
+
}
|
|
181
|
+
refElements.bindAll();
|
|
182
|
+
for (const v of refElements.values()) {
|
|
183
|
+
if (v.refCount > 0 && (!v.hasTag || !renderTagged || (v instanceof way_1.Way && excludeWay))) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
const features = v.toFeatureArray();
|
|
187
|
+
// return the first geometry of the first relation element
|
|
188
|
+
if (v instanceof relation_1.Relation && !completeFeature && features.length > 0) {
|
|
189
|
+
return features[0].geometry;
|
|
190
|
+
}
|
|
191
|
+
featureArray = featureArray.concat(features);
|
|
192
|
+
}
|
|
193
|
+
return { type: 'FeatureCollection', features: featureArray };
|
|
194
|
+
}
|
|
195
|
+
;
|
|
196
|
+
module.exports = osm2geojson;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LateBinder = void 0;
|
|
4
|
+
class LateBinder {
|
|
5
|
+
constructor(container, valueFunc, ctx, args) {
|
|
6
|
+
this.container = container;
|
|
7
|
+
this.valueFunc = valueFunc;
|
|
8
|
+
this.ctx = ctx;
|
|
9
|
+
this.args = args;
|
|
10
|
+
}
|
|
11
|
+
bind() {
|
|
12
|
+
const v = this.valueFunc.apply(this.ctx, this.args);
|
|
13
|
+
const idx = this.container.indexOf(this);
|
|
14
|
+
if (idx < 0) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const args = [idx, 1];
|
|
18
|
+
if (v) {
|
|
19
|
+
args.push(v);
|
|
20
|
+
}
|
|
21
|
+
Array.prototype.splice.apply(this.container, args);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.LateBinder = LateBinder;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { OsmObject } from "./osm-object";
|
|
2
|
+
import type { RefElements } from "./ref-elements";
|
|
3
|
+
import type { Feature } from "geojson";
|
|
4
|
+
export type LatLon = {
|
|
5
|
+
lat: string;
|
|
6
|
+
lon: string;
|
|
7
|
+
};
|
|
8
|
+
export declare class Node extends OsmObject {
|
|
9
|
+
private latLng;
|
|
10
|
+
constructor(id: string, refElems: RefElements);
|
|
11
|
+
setLatLng(latLng: LatLon): void;
|
|
12
|
+
toFeatureArray(): Array<Feature<any, any>>;
|
|
13
|
+
getLatLng(): LatLon | undefined;
|
|
14
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Node = void 0;
|
|
4
|
+
const osm_object_1 = require("./osm-object");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
class Node extends osm_object_1.OsmObject {
|
|
7
|
+
constructor(id, refElems) {
|
|
8
|
+
super('node', id, refElems);
|
|
9
|
+
}
|
|
10
|
+
setLatLng(latLng) {
|
|
11
|
+
this.latLng = latLng;
|
|
12
|
+
}
|
|
13
|
+
toFeatureArray() {
|
|
14
|
+
if (this.latLng) {
|
|
15
|
+
return [{
|
|
16
|
+
type: 'Feature',
|
|
17
|
+
id: this.getCompositeId(),
|
|
18
|
+
properties: this.getProps(),
|
|
19
|
+
geometry: {
|
|
20
|
+
type: 'Point',
|
|
21
|
+
coordinates: (0, utils_1.strArrayToFloat)([this.latLng.lon, this.latLng.lat]),
|
|
22
|
+
},
|
|
23
|
+
}];
|
|
24
|
+
}
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
getLatLng() {
|
|
28
|
+
return this.latLng;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.Node = Node;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { RefElements } from './ref-elements';
|
|
2
|
+
import type { Feature } from 'geojson';
|
|
3
|
+
export declare abstract class OsmObject {
|
|
4
|
+
refCount: number;
|
|
5
|
+
hasTag: boolean;
|
|
6
|
+
protected refElems: RefElements;
|
|
7
|
+
private type;
|
|
8
|
+
private id;
|
|
9
|
+
private tags;
|
|
10
|
+
private props;
|
|
11
|
+
constructor(type: string, id: string, refElems: RefElements);
|
|
12
|
+
addTags(tags: {
|
|
13
|
+
[k: string]: string;
|
|
14
|
+
}): void;
|
|
15
|
+
addTag(k: string, v: string): void;
|
|
16
|
+
addProp(k: string, v: any): void;
|
|
17
|
+
addProps(props: {
|
|
18
|
+
[k: string]: string;
|
|
19
|
+
}): void;
|
|
20
|
+
getCompositeId(): string;
|
|
21
|
+
getProps(): {
|
|
22
|
+
[k: string]: string;
|
|
23
|
+
};
|
|
24
|
+
abstract toFeatureArray(): Array<Feature<any, any>>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OsmObject = void 0;
|
|
4
|
+
class OsmObject {
|
|
5
|
+
constructor(type, id, refElems) {
|
|
6
|
+
this.type = type;
|
|
7
|
+
this.id = id;
|
|
8
|
+
this.refElems = refElems;
|
|
9
|
+
this.tags = {};
|
|
10
|
+
this.props = { id: this.getCompositeId() };
|
|
11
|
+
this.refCount = 0;
|
|
12
|
+
this.hasTag = false;
|
|
13
|
+
if (refElems) {
|
|
14
|
+
refElems.add(this.getCompositeId(), this);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
addTags(tags) {
|
|
18
|
+
this.tags = Object.assign(this.tags, tags);
|
|
19
|
+
this.hasTag = true;
|
|
20
|
+
}
|
|
21
|
+
addTag(k, v) {
|
|
22
|
+
this.tags[k] = v;
|
|
23
|
+
this.hasTag = true;
|
|
24
|
+
}
|
|
25
|
+
addProp(k, v) {
|
|
26
|
+
this.props[k] = v;
|
|
27
|
+
}
|
|
28
|
+
addProps(props) {
|
|
29
|
+
this.props = Object.assign(this.props, props);
|
|
30
|
+
}
|
|
31
|
+
getCompositeId() {
|
|
32
|
+
return `${this.type}/${this.id}`;
|
|
33
|
+
}
|
|
34
|
+
getProps() {
|
|
35
|
+
return Object.assign(this.props, this.tags);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.OsmObject = OsmObject;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"building": {},
|
|
3
|
+
"highway": {
|
|
4
|
+
"whitelist": [
|
|
5
|
+
"services",
|
|
6
|
+
"rest_area",
|
|
7
|
+
"escape",
|
|
8
|
+
"elevator"
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
"natural": {
|
|
12
|
+
"blacklist": [
|
|
13
|
+
"coastline",
|
|
14
|
+
"cliff",
|
|
15
|
+
"ridge",
|
|
16
|
+
"arete",
|
|
17
|
+
"tree_row"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"landuse": {},
|
|
21
|
+
"waterway": {
|
|
22
|
+
"whitelist": [
|
|
23
|
+
"riverbank",
|
|
24
|
+
"dock",
|
|
25
|
+
"boatyard",
|
|
26
|
+
"dam"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"amenity": {},
|
|
30
|
+
"leisure": {},
|
|
31
|
+
"barrier": {
|
|
32
|
+
"whitelist": [
|
|
33
|
+
"city_wall",
|
|
34
|
+
"ditch",
|
|
35
|
+
"hedge",
|
|
36
|
+
"retaining_wall",
|
|
37
|
+
"wall",
|
|
38
|
+
"spikes"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"railway": {
|
|
42
|
+
"whitelist": [
|
|
43
|
+
"station",
|
|
44
|
+
"turntable",
|
|
45
|
+
"roundhouse",
|
|
46
|
+
"platform"
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
"area": {},
|
|
50
|
+
"boundary": {},
|
|
51
|
+
"man_made": {
|
|
52
|
+
"blacklist": [
|
|
53
|
+
"cutline",
|
|
54
|
+
"embankment",
|
|
55
|
+
"pipeline"
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
"power": {
|
|
59
|
+
"whitelist": [
|
|
60
|
+
"plant",
|
|
61
|
+
"substation",
|
|
62
|
+
"generator",
|
|
63
|
+
"transformer"
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
"place": {},
|
|
67
|
+
"shop": {},
|
|
68
|
+
"aeroway": {
|
|
69
|
+
"blacklist": [
|
|
70
|
+
"taxiway"
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
"tourism": {},
|
|
74
|
+
"historic": {},
|
|
75
|
+
"public_transport": {},
|
|
76
|
+
"office": {},
|
|
77
|
+
"building:part": {},
|
|
78
|
+
"military": {},
|
|
79
|
+
"ruins": {},
|
|
80
|
+
"area:highway": {},
|
|
81
|
+
"craft": {},
|
|
82
|
+
"golf": {},
|
|
83
|
+
"indoor": {}
|
|
84
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { LateBinder } from "./late-binder";
|
|
2
|
+
import type { OsmObject } from "./osm-object";
|
|
3
|
+
export declare class RefElements extends Map<string, OsmObject> {
|
|
4
|
+
private binders;
|
|
5
|
+
constructor();
|
|
6
|
+
add(k: string, v: OsmObject): void;
|
|
7
|
+
addBinder(binder: LateBinder<any>): void;
|
|
8
|
+
bindAll(): void;
|
|
9
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RefElements = void 0;
|
|
4
|
+
class RefElements extends Map {
|
|
5
|
+
constructor() {
|
|
6
|
+
super();
|
|
7
|
+
this.binders = [];
|
|
8
|
+
}
|
|
9
|
+
add(k, v) {
|
|
10
|
+
this.set(k, v);
|
|
11
|
+
}
|
|
12
|
+
addBinder(binder) {
|
|
13
|
+
this.binders.push(binder);
|
|
14
|
+
}
|
|
15
|
+
bindAll() {
|
|
16
|
+
this.binders.forEach((binder) => binder.bind());
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.RefElements = RefElements;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { OsmObject } from "./osm-object";
|
|
2
|
+
import { Way } from "./way";
|
|
3
|
+
import { LateBinder } from "./late-binder";
|
|
4
|
+
import type { RefElements } from "./ref-elements";
|
|
5
|
+
import type { Feature } from "geojson";
|
|
6
|
+
export declare class Relation extends OsmObject {
|
|
7
|
+
private relations;
|
|
8
|
+
private nodes;
|
|
9
|
+
private bounds;
|
|
10
|
+
ways: (LateBinder<Way> | Way)[];
|
|
11
|
+
roles: string[];
|
|
12
|
+
constructor(id: string, refElems: RefElements);
|
|
13
|
+
setBounds(bounds: any[]): void;
|
|
14
|
+
addMember(member: {
|
|
15
|
+
[k: string]: any;
|
|
16
|
+
}): void;
|
|
17
|
+
private constructStringGeometry;
|
|
18
|
+
private constructPolygonGeometry;
|
|
19
|
+
toFeatureArray(): Array<Feature<any, any>>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Relation = void 0;
|
|
4
|
+
const osm_object_1 = require("./osm-object");
|
|
5
|
+
const way_1 = require("./way");
|
|
6
|
+
const node_1 = require("./node");
|
|
7
|
+
const way_collection_1 = require("./way-collection");
|
|
8
|
+
const late_binder_1 = require("./late-binder");
|
|
9
|
+
const utils_1 = require("./utils");
|
|
10
|
+
class Relation extends osm_object_1.OsmObject {
|
|
11
|
+
constructor(id, refElems) {
|
|
12
|
+
super('relation', id, refElems);
|
|
13
|
+
this.relations = [];
|
|
14
|
+
this.nodes = [];
|
|
15
|
+
this.bounds = undefined;
|
|
16
|
+
this.ways = [];
|
|
17
|
+
this.roles = [];
|
|
18
|
+
}
|
|
19
|
+
setBounds(bounds) {
|
|
20
|
+
this.bounds = bounds;
|
|
21
|
+
}
|
|
22
|
+
addMember(member) {
|
|
23
|
+
switch (member.type) {
|
|
24
|
+
// super relation, need to do combination
|
|
25
|
+
case 'relation':
|
|
26
|
+
let binder = new late_binder_1.LateBinder(this.relations, (id) => {
|
|
27
|
+
const relation = this.refElems.get(`relation/${id}`);
|
|
28
|
+
if (relation) {
|
|
29
|
+
relation.refCount++;
|
|
30
|
+
return relation;
|
|
31
|
+
}
|
|
32
|
+
}, this, [member.ref]);
|
|
33
|
+
this.relations.push(binder);
|
|
34
|
+
this.refElems.addBinder(binder);
|
|
35
|
+
break;
|
|
36
|
+
case 'way':
|
|
37
|
+
if (!member.role) {
|
|
38
|
+
member.role = '';
|
|
39
|
+
}
|
|
40
|
+
if (member.geometry) {
|
|
41
|
+
const way = new way_1.Way(member.ref, this.refElems);
|
|
42
|
+
way.setLatLngArray(member.geometry);
|
|
43
|
+
way.refCount++;
|
|
44
|
+
this.ways.push(way);
|
|
45
|
+
this.roles.push(member.role);
|
|
46
|
+
}
|
|
47
|
+
else if (member.nodes) {
|
|
48
|
+
const way = new way_1.Way(member.ref, this.refElems);
|
|
49
|
+
for (const nid of member.nodes) {
|
|
50
|
+
way.addNodeRef(nid);
|
|
51
|
+
}
|
|
52
|
+
way.refCount++;
|
|
53
|
+
this.ways.push(way);
|
|
54
|
+
this.roles.push(member.role);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
let binder = new late_binder_1.LateBinder(this.ways, (nid) => {
|
|
58
|
+
const way = this.refElems.get(`way/${nid}`);
|
|
59
|
+
if (way) {
|
|
60
|
+
way.refCount++;
|
|
61
|
+
return way;
|
|
62
|
+
}
|
|
63
|
+
}, this, [member.ref]);
|
|
64
|
+
this.ways.push(binder);
|
|
65
|
+
this.roles.push(member.role);
|
|
66
|
+
this.refElems.addBinder(binder);
|
|
67
|
+
}
|
|
68
|
+
break;
|
|
69
|
+
case 'node':
|
|
70
|
+
let node = null;
|
|
71
|
+
if (member.lat && member.lon) {
|
|
72
|
+
node = new node_1.Node(member.ref, this.refElems);
|
|
73
|
+
node.setLatLng({ lon: member.lon, lat: member.lat });
|
|
74
|
+
if (member.tags) {
|
|
75
|
+
node.addTags(member.tags);
|
|
76
|
+
}
|
|
77
|
+
for (const [k, v] of Object.entries(member)) {
|
|
78
|
+
if (['id', 'type', 'lat', 'lon'].indexOf(k) < 0) {
|
|
79
|
+
node.addProp(k, v);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
node.refCount++;
|
|
83
|
+
this.nodes.push(node);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
let binder = new late_binder_1.LateBinder(this.nodes, (id) => {
|
|
87
|
+
const nn = this.refElems.get(`node/${id}`);
|
|
88
|
+
if (nn) {
|
|
89
|
+
nn.refCount++;
|
|
90
|
+
return nn;
|
|
91
|
+
}
|
|
92
|
+
}, this, [member.ref]);
|
|
93
|
+
this.nodes.push(binder);
|
|
94
|
+
this.refElems.addBinder(binder);
|
|
95
|
+
}
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
constructStringGeometry(ws) {
|
|
100
|
+
const strings = ws ? ws.mergeWays() : [];
|
|
101
|
+
if (strings.length === 0) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
type: 'MultiLineString',
|
|
106
|
+
coordinates: strings,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
constructPolygonGeometry(ows, iws) {
|
|
110
|
+
const outerRings = ows ? ows.toRings('counterclockwise') : [];
|
|
111
|
+
const innerRings = iws ? iws.toRings('clockwise') : [];
|
|
112
|
+
if (outerRings.length > 0) {
|
|
113
|
+
const compositPolyons = [];
|
|
114
|
+
let ring;
|
|
115
|
+
for (ring of outerRings) {
|
|
116
|
+
compositPolyons.push([ring]);
|
|
117
|
+
}
|
|
118
|
+
// link inner polygons to outer containers
|
|
119
|
+
ring = innerRings.shift();
|
|
120
|
+
while (ring) {
|
|
121
|
+
for (const idx in outerRings) {
|
|
122
|
+
if ((0, utils_1.pointInsidePolygon)((0, utils_1.first)(ring), outerRings[idx])) {
|
|
123
|
+
compositPolyons[idx].push(ring);
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
ring = innerRings.shift();
|
|
128
|
+
}
|
|
129
|
+
// construct the Polygon/MultiPolygon geometry
|
|
130
|
+
if (compositPolyons.length === 1) {
|
|
131
|
+
return {
|
|
132
|
+
type: 'Polygon',
|
|
133
|
+
coordinates: compositPolyons[0],
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
type: 'MultiPolygon',
|
|
138
|
+
coordinates: compositPolyons,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
toFeatureArray() {
|
|
144
|
+
const polygonFeatures = [];
|
|
145
|
+
const stringFeatures = [];
|
|
146
|
+
let pointFeatures = [];
|
|
147
|
+
for (const relation of this.relations) {
|
|
148
|
+
if (!relation) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
for (let i = 0; i < relation.ways.length; i++) {
|
|
152
|
+
const way = relation.ways[i];
|
|
153
|
+
this.ways.push(way);
|
|
154
|
+
this.roles.push(relation.roles[i]);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
let templateFeature = {
|
|
158
|
+
type: 'Feature',
|
|
159
|
+
id: this.getCompositeId(),
|
|
160
|
+
bbox: this.bounds,
|
|
161
|
+
properties: this.getProps(),
|
|
162
|
+
geometry: null
|
|
163
|
+
};
|
|
164
|
+
if (!this.bounds) {
|
|
165
|
+
delete templateFeature.bbox;
|
|
166
|
+
}
|
|
167
|
+
if (this.roles.some((r) => r === 'outer')) {
|
|
168
|
+
const outerWayCollection = new way_collection_1.WayCollection();
|
|
169
|
+
const innerWayCollection = new way_collection_1.WayCollection();
|
|
170
|
+
for (let i = 0; i < this.ways.length; i++) {
|
|
171
|
+
const way = this.ways[i];
|
|
172
|
+
const role = this.roles[i];
|
|
173
|
+
if (role === 'outer') {
|
|
174
|
+
outerWayCollection.addWay(way);
|
|
175
|
+
}
|
|
176
|
+
else if (role === 'inner') {
|
|
177
|
+
innerWayCollection.addWay(way);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
let feature = Object.assign({}, templateFeature);
|
|
181
|
+
let geometry = this.constructPolygonGeometry(outerWayCollection, innerWayCollection);
|
|
182
|
+
if (geometry) {
|
|
183
|
+
feature.geometry = geometry;
|
|
184
|
+
polygonFeatures.push(feature);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
const wayCollection = new way_collection_1.WayCollection();
|
|
189
|
+
for (let way of this.ways) {
|
|
190
|
+
wayCollection.addWay(way);
|
|
191
|
+
}
|
|
192
|
+
let geometry = this.constructStringGeometry(wayCollection);
|
|
193
|
+
if (geometry) {
|
|
194
|
+
let feature = Object.assign({}, templateFeature);
|
|
195
|
+
feature.geometry = geometry;
|
|
196
|
+
stringFeatures.push(feature);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
for (let node of this.nodes) {
|
|
200
|
+
pointFeatures = pointFeatures.concat(node.toFeatureArray());
|
|
201
|
+
}
|
|
202
|
+
return [...polygonFeatures, ...stringFeatures, ...pointFeatures];
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
exports.Relation = Relation;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare function purgeProps(obj: {
|
|
2
|
+
[k: string]: any;
|
|
3
|
+
}, blacklist: string[]): {
|
|
4
|
+
[k: string]: any;
|
|
5
|
+
};
|
|
6
|
+
export declare function first<T>(a: T[]): T;
|
|
7
|
+
export declare function last<T>(a: T[]): T;
|
|
8
|
+
export declare function coordsToKey<T>(a: T[]): string;
|
|
9
|
+
export declare function addToMap<T>(m: {
|
|
10
|
+
[k: string]: T[];
|
|
11
|
+
}, k: string, v: T): void;
|
|
12
|
+
export declare function removeFromMap<T>(m: {
|
|
13
|
+
[k: string]: T[];
|
|
14
|
+
}, k: string, v: T): void;
|
|
15
|
+
export declare function getFirstFromMap<T>(m: {
|
|
16
|
+
[k: string]: T[];
|
|
17
|
+
}, k: string): T | null;
|
|
18
|
+
export declare function isRing(a: number[][]): boolean;
|
|
19
|
+
export declare function ringDirection(a: number[][], xIdx?: number, yIdx?: number): string;
|
|
20
|
+
export declare function pointInsidePolygon(pt: number[], polygon: number[][], xIdx?: number, yIdx?: number): boolean;
|
|
21
|
+
export declare function strArrayArrayToFloat(el: string[][]): number[][];
|
|
22
|
+
export declare function strArrayToFloat(el: string[]): number[];
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.purgeProps = purgeProps;
|
|
4
|
+
exports.first = first;
|
|
5
|
+
exports.last = last;
|
|
6
|
+
exports.coordsToKey = coordsToKey;
|
|
7
|
+
exports.addToMap = addToMap;
|
|
8
|
+
exports.removeFromMap = removeFromMap;
|
|
9
|
+
exports.getFirstFromMap = getFirstFromMap;
|
|
10
|
+
exports.isRing = isRing;
|
|
11
|
+
exports.ringDirection = ringDirection;
|
|
12
|
+
exports.pointInsidePolygon = pointInsidePolygon;
|
|
13
|
+
exports.strArrayArrayToFloat = strArrayArrayToFloat;
|
|
14
|
+
exports.strArrayToFloat = strArrayToFloat;
|
|
15
|
+
function purgeProps(obj, blacklist) {
|
|
16
|
+
if (obj) {
|
|
17
|
+
const rs = Object.assign({}, obj);
|
|
18
|
+
if (blacklist) {
|
|
19
|
+
for (const prop of blacklist) {
|
|
20
|
+
delete rs[prop];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return rs;
|
|
24
|
+
}
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
function first(a) { return a[0]; }
|
|
28
|
+
function last(a) { return a[a.length - 1]; }
|
|
29
|
+
function coordsToKey(a) { return a.join(','); }
|
|
30
|
+
function addToMap(m, k, v) {
|
|
31
|
+
const a = m[k];
|
|
32
|
+
if (a) {
|
|
33
|
+
a.push(v);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
m[k] = [v];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function removeFromMap(m, k, v) {
|
|
40
|
+
const a = m[k];
|
|
41
|
+
let idx = -1;
|
|
42
|
+
if (a) {
|
|
43
|
+
idx = a.indexOf(v);
|
|
44
|
+
}
|
|
45
|
+
if (idx >= 0) {
|
|
46
|
+
a.splice(idx, 1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function getFirstFromMap(m, k) {
|
|
50
|
+
const a = m[k];
|
|
51
|
+
if (a && a.length > 0) {
|
|
52
|
+
return a[0];
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
// need 3+ different points to form a ring, here using > 3 is 'coz a the first and the last points are actually the same
|
|
57
|
+
function isRing(a) {
|
|
58
|
+
return a.length > 3 && coordsToKey(first(a)) === coordsToKey(last(a));
|
|
59
|
+
}
|
|
60
|
+
function ringDirection(a, xIdx, yIdx) {
|
|
61
|
+
xIdx = xIdx || 0, yIdx = yIdx || 1;
|
|
62
|
+
// get the index of the point which has the maximum x value
|
|
63
|
+
const m = a.reduce((maxxIdx, v, idx) => a[maxxIdx][xIdx || 0] > v[xIdx || 0] ? maxxIdx : idx, 0);
|
|
64
|
+
// 'coz the first point is virtually the same one as the last point,
|
|
65
|
+
// we need to skip a.length - 1 for left when m = 0,
|
|
66
|
+
// and skip 0 for right when m = a.length - 1;
|
|
67
|
+
const l = m <= 0 ? a.length - 2 : m - 1;
|
|
68
|
+
const r = m >= a.length - 1 ? 1 : m + 1;
|
|
69
|
+
const xa = a[l][xIdx];
|
|
70
|
+
const xb = a[m][xIdx];
|
|
71
|
+
const xc = a[r][xIdx];
|
|
72
|
+
const ya = a[l][yIdx];
|
|
73
|
+
const yb = a[m][yIdx];
|
|
74
|
+
const yc = a[r][yIdx];
|
|
75
|
+
const det = (xb - xa) * (yc - ya) - (xc - xa) * (yb - ya);
|
|
76
|
+
return det < 0 ? 'clockwise' : 'counterclockwise';
|
|
77
|
+
}
|
|
78
|
+
;
|
|
79
|
+
function pointInsidePolygon(pt, polygon, xIdx, yIdx) {
|
|
80
|
+
xIdx = xIdx || 0, yIdx = yIdx || 1;
|
|
81
|
+
let result = false;
|
|
82
|
+
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
|
83
|
+
if ((polygon[i][xIdx] <= pt[xIdx] && pt[xIdx] < polygon[j][xIdx] ||
|
|
84
|
+
polygon[j][xIdx] <= pt[xIdx] && pt[xIdx] < polygon[i][xIdx]) &&
|
|
85
|
+
pt[yIdx] < (polygon[j][yIdx] - polygon[i][yIdx]) * (pt[xIdx] - polygon[i][xIdx]) / (polygon[j][xIdx] - polygon[i][xIdx]) + polygon[i][yIdx]) {
|
|
86
|
+
result = !result;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
;
|
|
92
|
+
function strArrayArrayToFloat(el) {
|
|
93
|
+
return el.map(strArrayToFloat);
|
|
94
|
+
}
|
|
95
|
+
function strArrayToFloat(el) {
|
|
96
|
+
return el.map(parseFloat);
|
|
97
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Way } from "./way";
|
|
2
|
+
export declare class WayCollection extends Array {
|
|
3
|
+
private firstMap;
|
|
4
|
+
private lastMap;
|
|
5
|
+
constructor();
|
|
6
|
+
addWay(way: Way): void;
|
|
7
|
+
mergeWays(): number[][][];
|
|
8
|
+
/**
|
|
9
|
+
* Try to find the next way to add to the current way.
|
|
10
|
+
* It first tries the next way in the array, and if this doesn't work, try any other way.
|
|
11
|
+
*/
|
|
12
|
+
private getNextWay;
|
|
13
|
+
toRings(direction: string): number[][][];
|
|
14
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WayCollection = void 0;
|
|
4
|
+
const utils_1 = require("./utils");
|
|
5
|
+
class WayCollection extends Array {
|
|
6
|
+
constructor() {
|
|
7
|
+
super();
|
|
8
|
+
this.firstMap = {};
|
|
9
|
+
this.lastMap = {};
|
|
10
|
+
}
|
|
11
|
+
addWay(way) {
|
|
12
|
+
const w = way.toCoordsArray();
|
|
13
|
+
if (w.length > 0) {
|
|
14
|
+
this.push(w);
|
|
15
|
+
(0, utils_1.addToMap)(this.firstMap, (0, utils_1.coordsToKey)((0, utils_1.first)(w)), w);
|
|
16
|
+
(0, utils_1.addToMap)(this.lastMap, (0, utils_1.coordsToKey)((0, utils_1.last)(w)), w);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
mergeWays() {
|
|
20
|
+
const strings = [];
|
|
21
|
+
let way = this.shift();
|
|
22
|
+
while (way) {
|
|
23
|
+
(0, utils_1.removeFromMap)(this.firstMap, (0, utils_1.coordsToKey)((0, utils_1.first)(way)), way);
|
|
24
|
+
(0, utils_1.removeFromMap)(this.lastMap, (0, utils_1.coordsToKey)((0, utils_1.last)(way)), way);
|
|
25
|
+
let current = way;
|
|
26
|
+
let next;
|
|
27
|
+
do {
|
|
28
|
+
let nextWay = this.getNextWay(current);
|
|
29
|
+
next = nextWay.next;
|
|
30
|
+
let mergeType = nextWay.mergeType;
|
|
31
|
+
if (!next) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
this.splice(this.indexOf(next), 1);
|
|
35
|
+
(0, utils_1.removeFromMap)(this.firstMap, (0, utils_1.coordsToKey)((0, utils_1.first)(next)), next);
|
|
36
|
+
(0, utils_1.removeFromMap)(this.lastMap, (0, utils_1.coordsToKey)((0, utils_1.last)(next)), next);
|
|
37
|
+
switch (mergeType) {
|
|
38
|
+
case 0 /* MergeType.EndStart */:
|
|
39
|
+
current = current.concat(next.slice(1));
|
|
40
|
+
break;
|
|
41
|
+
case 1 /* MergeType.EndEnd */:
|
|
42
|
+
next.reverse();
|
|
43
|
+
current = current.concat(next.slice(1));
|
|
44
|
+
break;
|
|
45
|
+
case 2 /* MergeType.StartStart */:
|
|
46
|
+
current.reverse();
|
|
47
|
+
current = current.concat(next.slice(1));
|
|
48
|
+
break;
|
|
49
|
+
case 3 /* MergeType.StartEnd */:
|
|
50
|
+
current = next.concat(current.slice(1));
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
} while (next);
|
|
54
|
+
strings.push((0, utils_1.strArrayArrayToFloat)(current));
|
|
55
|
+
way = this.shift();
|
|
56
|
+
}
|
|
57
|
+
return strings;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Try to find the next way to add to the current way.
|
|
61
|
+
* It first tries the next way in the array, and if this doesn't work, try any other way.
|
|
62
|
+
*/
|
|
63
|
+
getNextWay(current) {
|
|
64
|
+
const lastKey = (0, utils_1.coordsToKey)((0, utils_1.last)(current));
|
|
65
|
+
const firstKey = (0, utils_1.coordsToKey)((0, utils_1.first)(current));
|
|
66
|
+
// Step 1: Prefer the next way in the array if it connects
|
|
67
|
+
let next = this.length > 0 ? this[0] : null;
|
|
68
|
+
if (next) {
|
|
69
|
+
const nextFirstKey = (0, utils_1.coordsToKey)((0, utils_1.first)(next));
|
|
70
|
+
const nextLastKey = (0, utils_1.coordsToKey)((0, utils_1.last)(next));
|
|
71
|
+
if (lastKey === nextFirstKey) {
|
|
72
|
+
return { next, mergeType: 0 /* MergeType.EndStart */ };
|
|
73
|
+
}
|
|
74
|
+
if (lastKey === nextLastKey) {
|
|
75
|
+
return { next, mergeType: 1 /* MergeType.EndEnd */ };
|
|
76
|
+
}
|
|
77
|
+
if (firstKey === nextFirstKey) {
|
|
78
|
+
return { next, mergeType: 2 /* MergeType.StartStart */ };
|
|
79
|
+
}
|
|
80
|
+
if (firstKey === nextLastKey) {
|
|
81
|
+
return { next, mergeType: 3 /* MergeType.StartEnd */ };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Step 2: Fallback to map-based lookup if no sequential match
|
|
85
|
+
next = (0, utils_1.getFirstFromMap)(this.firstMap, lastKey);
|
|
86
|
+
if (next) {
|
|
87
|
+
return { next, mergeType: 0 /* MergeType.EndStart */ };
|
|
88
|
+
}
|
|
89
|
+
next = (0, utils_1.getFirstFromMap)(this.lastMap, lastKey);
|
|
90
|
+
return { next, mergeType: 1 /* MergeType.EndEnd */ };
|
|
91
|
+
}
|
|
92
|
+
toRings(direction) {
|
|
93
|
+
const strings = this.mergeWays();
|
|
94
|
+
const rings = [];
|
|
95
|
+
let str = strings.shift();
|
|
96
|
+
while (str) {
|
|
97
|
+
if ((0, utils_1.isRing)(str)) {
|
|
98
|
+
if ((0, utils_1.ringDirection)(str) !== direction) {
|
|
99
|
+
str.reverse();
|
|
100
|
+
}
|
|
101
|
+
rings.push(str);
|
|
102
|
+
}
|
|
103
|
+
str = strings.shift();
|
|
104
|
+
}
|
|
105
|
+
return rings;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
exports.WayCollection = WayCollection;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Feature } from "geojson";
|
|
2
|
+
import { OsmObject } from "./osm-object";
|
|
3
|
+
import { LatLon } from "./node";
|
|
4
|
+
import type { RefElements } from "./ref-elements";
|
|
5
|
+
export declare class Way extends OsmObject {
|
|
6
|
+
private latLngArray;
|
|
7
|
+
private isPolygon;
|
|
8
|
+
constructor(id: string, refElems: RefElements);
|
|
9
|
+
addLatLng(latLng: LatLon): void;
|
|
10
|
+
setLatLngArray(latLngArray: Array<LatLon & {
|
|
11
|
+
[k: string]: any;
|
|
12
|
+
}>): void;
|
|
13
|
+
addNodeRef(ref: string): void;
|
|
14
|
+
addTags(tags: {
|
|
15
|
+
[k: string]: string;
|
|
16
|
+
}): void;
|
|
17
|
+
addTag(k: string, v: string): void;
|
|
18
|
+
toCoordsArray(): string[][];
|
|
19
|
+
toFeatureArray(): Array<Feature<any, any>>;
|
|
20
|
+
private analyzeTag;
|
|
21
|
+
}
|
package/dist/node/way.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Way = void 0;
|
|
7
|
+
const osm_object_1 = require("./osm-object");
|
|
8
|
+
const late_binder_1 = require("./late-binder");
|
|
9
|
+
const utils_1 = require("./utils");
|
|
10
|
+
const polytags_json_1 = __importDefault(require("./polytags.json"));
|
|
11
|
+
class Way extends osm_object_1.OsmObject {
|
|
12
|
+
constructor(id, refElems) {
|
|
13
|
+
super('way', id, refElems);
|
|
14
|
+
this.latLngArray = [];
|
|
15
|
+
this.isPolygon = false;
|
|
16
|
+
}
|
|
17
|
+
addLatLng(latLng) {
|
|
18
|
+
this.latLngArray.push(latLng);
|
|
19
|
+
}
|
|
20
|
+
setLatLngArray(latLngArray) {
|
|
21
|
+
this.latLngArray = latLngArray;
|
|
22
|
+
}
|
|
23
|
+
addNodeRef(ref) {
|
|
24
|
+
const binder = new late_binder_1.LateBinder(this.latLngArray, (id) => {
|
|
25
|
+
const node = this.refElems.get(`node/${id}`);
|
|
26
|
+
if (node) {
|
|
27
|
+
node.refCount++;
|
|
28
|
+
return node.getLatLng();
|
|
29
|
+
}
|
|
30
|
+
}, this, [ref]);
|
|
31
|
+
this.latLngArray.push(binder);
|
|
32
|
+
this.refElems.addBinder(binder);
|
|
33
|
+
}
|
|
34
|
+
addTags(tags) {
|
|
35
|
+
super.addTags(tags);
|
|
36
|
+
for (const [k, v] of Object.entries(tags)) {
|
|
37
|
+
this.analyzeTag(k, v);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
addTag(k, v) {
|
|
41
|
+
super.addTag(k, v);
|
|
42
|
+
this.analyzeTag(k, v);
|
|
43
|
+
}
|
|
44
|
+
toCoordsArray() {
|
|
45
|
+
return this.latLngArray.map((latLng) => [latLng.lon, latLng.lat]);
|
|
46
|
+
}
|
|
47
|
+
toFeatureArray() {
|
|
48
|
+
let coordsArrayString = this.toCoordsArray();
|
|
49
|
+
if (coordsArrayString.length > 1) {
|
|
50
|
+
const coordsArray = (0, utils_1.strArrayArrayToFloat)(coordsArrayString);
|
|
51
|
+
const feature = {
|
|
52
|
+
type: 'Feature',
|
|
53
|
+
id: this.getCompositeId(),
|
|
54
|
+
properties: this.getProps(),
|
|
55
|
+
geometry: {
|
|
56
|
+
type: 'LineString',
|
|
57
|
+
coordinates: coordsArray,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
if (this.isPolygon && (0, utils_1.isRing)(coordsArray)) {
|
|
61
|
+
if ((0, utils_1.ringDirection)(coordsArray) !== 'counterclockwise') {
|
|
62
|
+
coordsArray.reverse();
|
|
63
|
+
}
|
|
64
|
+
feature.geometry = {
|
|
65
|
+
type: 'Polygon',
|
|
66
|
+
coordinates: [coordsArray],
|
|
67
|
+
};
|
|
68
|
+
return [feature];
|
|
69
|
+
}
|
|
70
|
+
return [feature];
|
|
71
|
+
}
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
analyzeTag(k, v) {
|
|
75
|
+
const o = polytags_json_1.default[k];
|
|
76
|
+
if (o) {
|
|
77
|
+
this.isPolygon = true;
|
|
78
|
+
if (o.whitelist) {
|
|
79
|
+
this.isPolygon = o.whitelist.indexOf(v) >= 0 ? true : false;
|
|
80
|
+
}
|
|
81
|
+
else if (o.blacklist) {
|
|
82
|
+
this.isPolygon = o.blacklist.indexOf(v) >= 0 ? false : true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
exports.Way = Way;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare class XmlParser {
|
|
2
|
+
private queryParent;
|
|
3
|
+
private progressive;
|
|
4
|
+
private parentMap;
|
|
5
|
+
private evtListeners;
|
|
6
|
+
constructor(opts: any);
|
|
7
|
+
parse(xml: string, parent?: any, dir?: string): any[];
|
|
8
|
+
getParent(node: any): any;
|
|
9
|
+
addListener(evt: string, func: (node: {
|
|
10
|
+
[k: string]: any;
|
|
11
|
+
}, parent?: {
|
|
12
|
+
[k: string]: any;
|
|
13
|
+
}) => void): void;
|
|
14
|
+
removeListener(evt: string, func: (node: {
|
|
15
|
+
[k: string]: any;
|
|
16
|
+
}, parent?: {
|
|
17
|
+
[k: string]: any;
|
|
18
|
+
}) => void): void;
|
|
19
|
+
on(evt: string, func: (node: {
|
|
20
|
+
[k: string]: any;
|
|
21
|
+
}, parent?: {
|
|
22
|
+
[k: string]: any;
|
|
23
|
+
}) => void): void;
|
|
24
|
+
off(evt: string, func: (node: {
|
|
25
|
+
[k: string]: any;
|
|
26
|
+
}, parent?: {
|
|
27
|
+
[k: string]: any;
|
|
28
|
+
}) => void): void;
|
|
29
|
+
private $addListener;
|
|
30
|
+
private $removeListener;
|
|
31
|
+
private emit;
|
|
32
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.XmlParser = void 0;
|
|
4
|
+
function conditioned(evt) {
|
|
5
|
+
return evt.match(/^(.+?)\[(.+?)\]>$/g) !== null;
|
|
6
|
+
}
|
|
7
|
+
function parseEvent(evt) {
|
|
8
|
+
const match = /^(.+?)\[(.+?)\]>$/g.exec(evt);
|
|
9
|
+
if (match) {
|
|
10
|
+
return { evt: match[1] + '>', exp: match[2] };
|
|
11
|
+
}
|
|
12
|
+
return { evt };
|
|
13
|
+
}
|
|
14
|
+
function genConditionFunc(cond) {
|
|
15
|
+
const body = 'return ' + cond.replace(/(\$.+?)(?=[=!.])/g, 'node.$&') + ';';
|
|
16
|
+
return new Function('node', body);
|
|
17
|
+
}
|
|
18
|
+
class XmlParser {
|
|
19
|
+
constructor(opts) {
|
|
20
|
+
this.queryParent = false;
|
|
21
|
+
this.progressive = false;
|
|
22
|
+
this.parentMap = new WeakMap();
|
|
23
|
+
if (opts) {
|
|
24
|
+
this.queryParent = opts.queryParent ? true : false;
|
|
25
|
+
this.progressive = opts.progressive;
|
|
26
|
+
if (this.queryParent) {
|
|
27
|
+
this.parentMap = new WeakMap();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
this.evtListeners = {};
|
|
31
|
+
}
|
|
32
|
+
parse(xml, parent, dir) {
|
|
33
|
+
dir = dir ? dir + '.' : '';
|
|
34
|
+
const nodeRegEx = /<([^ >\/]+)(.*?)>/mg;
|
|
35
|
+
const nodes = [];
|
|
36
|
+
let nodeMatch = nodeRegEx.exec(xml);
|
|
37
|
+
while (nodeMatch) {
|
|
38
|
+
const tag = nodeMatch[1];
|
|
39
|
+
const node = { $tag: tag };
|
|
40
|
+
const fullTag = dir + tag;
|
|
41
|
+
const attrText = nodeMatch[2].trim();
|
|
42
|
+
let closed = false;
|
|
43
|
+
if (attrText.endsWith('/') || tag.startsWith('?') || tag.startsWith('!')) {
|
|
44
|
+
closed = true;
|
|
45
|
+
}
|
|
46
|
+
const attRegEx1 = /([^ ]+?)="(.+?)"/g;
|
|
47
|
+
const attRegEx2 = /([^ ]+?)='(.+?)'/g;
|
|
48
|
+
let attMatch = attRegEx1.exec(attrText);
|
|
49
|
+
let hasAttrs = false;
|
|
50
|
+
while (attMatch) {
|
|
51
|
+
hasAttrs = true;
|
|
52
|
+
node[attMatch[1]] = attMatch[2];
|
|
53
|
+
attMatch = attRegEx1.exec(attrText);
|
|
54
|
+
}
|
|
55
|
+
if (!hasAttrs) {
|
|
56
|
+
attMatch = attRegEx2.exec(attrText);
|
|
57
|
+
while (attMatch) {
|
|
58
|
+
hasAttrs = true;
|
|
59
|
+
node[attMatch[1]] = attMatch[2];
|
|
60
|
+
attMatch = attRegEx2.exec(attrText);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (!hasAttrs && attrText !== '') {
|
|
64
|
+
node.text = attrText;
|
|
65
|
+
}
|
|
66
|
+
if (this.progressive) {
|
|
67
|
+
this.emit(`<${fullTag}>`, node, parent);
|
|
68
|
+
}
|
|
69
|
+
if (!closed) {
|
|
70
|
+
const innerRegEx = new RegExp(`([^]+?)<\/${tag}>`, 'g');
|
|
71
|
+
innerRegEx.lastIndex = nodeRegEx.lastIndex;
|
|
72
|
+
const innerMatch = innerRegEx.exec(xml);
|
|
73
|
+
if (innerMatch && innerMatch[1]) {
|
|
74
|
+
nodeRegEx.lastIndex = innerRegEx.lastIndex;
|
|
75
|
+
const innerNodes = this.parse(innerMatch[1], node, fullTag);
|
|
76
|
+
if (innerNodes.length > 0) {
|
|
77
|
+
node.$innerNodes = innerNodes;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
node.$innerText = innerMatch[1];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (this.queryParent && parent) {
|
|
85
|
+
this.parentMap.set(node, parent);
|
|
86
|
+
}
|
|
87
|
+
if (this.progressive) {
|
|
88
|
+
this.emit(`</${fullTag}>`, node, parent);
|
|
89
|
+
}
|
|
90
|
+
nodes.push(node);
|
|
91
|
+
nodeMatch = nodeRegEx.exec(xml);
|
|
92
|
+
}
|
|
93
|
+
return nodes;
|
|
94
|
+
}
|
|
95
|
+
getParent(node) {
|
|
96
|
+
if (this.queryParent) {
|
|
97
|
+
return this.parentMap.get(node);
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
// support javascript condition for the last tag
|
|
102
|
+
addListener(evt, func) {
|
|
103
|
+
if (conditioned(evt)) {
|
|
104
|
+
// func.prototype = evt;
|
|
105
|
+
const ev = parseEvent(evt);
|
|
106
|
+
if (ev.exp) {
|
|
107
|
+
func.condition = genConditionFunc(ev.exp);
|
|
108
|
+
}
|
|
109
|
+
evt = ev.evt;
|
|
110
|
+
}
|
|
111
|
+
this.$addListener(evt, func);
|
|
112
|
+
}
|
|
113
|
+
removeListener(evt, func) {
|
|
114
|
+
if (conditioned(evt)) {
|
|
115
|
+
const ev = parseEvent(evt);
|
|
116
|
+
evt = ev.evt;
|
|
117
|
+
}
|
|
118
|
+
this.$removeListener(evt, func);
|
|
119
|
+
}
|
|
120
|
+
on(evt, func) {
|
|
121
|
+
this.addListener(evt, func);
|
|
122
|
+
}
|
|
123
|
+
off(evt, func) {
|
|
124
|
+
this.removeListener(evt, func);
|
|
125
|
+
}
|
|
126
|
+
$addListener(evt, func) {
|
|
127
|
+
const funcs = this.evtListeners[evt];
|
|
128
|
+
if (funcs) {
|
|
129
|
+
funcs.push(func);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
this.evtListeners[evt] = [func];
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
$removeListener(evt, func) {
|
|
136
|
+
const funcs = this.evtListeners[evt];
|
|
137
|
+
let idx = -1;
|
|
138
|
+
if (funcs) {
|
|
139
|
+
idx = funcs.indexOf(func);
|
|
140
|
+
}
|
|
141
|
+
if (idx >= 0) {
|
|
142
|
+
funcs.splice(idx, 1);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
emit(evt, ...args) {
|
|
146
|
+
const funcs = this.evtListeners[evt];
|
|
147
|
+
if (funcs) {
|
|
148
|
+
for (const func of funcs) {
|
|
149
|
+
if (func.condition) {
|
|
150
|
+
if (func.condition.apply(null, args) === true) {
|
|
151
|
+
func.apply(null, args);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
func.apply(null, args);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
exports.XmlParser = XmlParser;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).osm2geojson=e()}(function(){return function s(o,i,n){function a(t,e){if(!i[t]){if(!o[t]){var r="function"==typeof require&&require;if(!e&&r)return r(t,!0);if(l)return l(t,!0);throw(e=new Error("Cannot find module '"+t+"'")).code="MODULE_NOT_FOUND",e}r=i[t]={exports:{}},o[t][0].call(r.exports,function(e){return a(o[t][1][e]||e)},r,r.exports,s,o,i,n)}return i[t].exports}for(var l="function"==typeof require&&require,e=0;e<n.length;e++)a(n[e]);return a}({1:[function(e,t,r){let v=e("./utils"),b=e("./xmlparser"),w=e("./node"),x=e("./way"),L=e("./relation"),T=e("./ref-elements");t.exports=function(e,t){var{completeFeature:r,renderTagged:s,excludeWay:o}=(t=t)?(a=void 0===t.excludeWay||t.excludeWay,{completeFeature:!!t.completeFeature,renderTagged:!!t.renderTagged,excludeWay:a}):{completeFeature:!1,renderTagged:!1,excludeWay:!0};let i=(t=e).elements?"json":0<=t.indexOf("<osm")?"xml":t.trim().startsWith("{")?"json-raw":"invalid";var l,n,a=new T.RefElements;let d=[];if("json-raw"===i&&(e=JSON.parse(e),i=e.elements?"json":"invalid"),"json"===i){var u,h=a;for(u of e.elements)switch(u.type){case"node":var f=new w.Node(u.id,h);u.tags&&f.addTags(u.tags),f.addProps((0,v.purgeProps)(u,["id","type","tags","lat","lon"])),f.setLatLng(u);break;case"way":var c=new x.Way(u.id,h);if(u.tags&&c.addTags(u.tags),c.addProps((0,v.purgeProps)(u,["id","type","tags","nodes","geometry"])),u.geometry)c.setLatLngArray(u.geometry);else if(u.nodes)for(var p of u.nodes)c.addNodeRef(p);break;case"relation":var g=new L.Relation(u.id,h);if(u.bounds&&g.setBounds([parseFloat(u.bounds.minlon),parseFloat(u.bounds.minlat),parseFloat(u.bounds.maxlon),parseFloat(u.bounds.maxlat)]),u.tags&&g.addTags(u.tags),g.addProps((0,v.purgeProps)(u,["id","type","tags","bounds","members"])),u.members)for(var y of u.members)g.addMember(y)}}else"xml"===i&&(t=e,l=a,(e=new b.XmlParser({progressive:!0})).on("</osm.node>",e=>{var t,r,s=new w.Node(e.id,l);for([t,r]of Object.entries(e))!t.startsWith("$")&&["id","lon","lat"].indexOf(t)<0&&s.addProp(t,r);if(s.setLatLng(e),e.$innerNodes)for(var o of e.$innerNodes)"tag"===o.$tag&&s.addTag(o.k,o.v)}),e.on("</osm.way>",e=>{var t,r,s=new x.Way(e.id,l);for([t,r]of Object.entries(e))!t.startsWith("$")&&["id"].indexOf(t)<0&&s.addProp(t,r);if(e.$innerNodes)for(var o of e.$innerNodes)"nd"===o.$tag?o.lon&&o.lat?s.addLatLng(o):o.ref&&s.addNodeRef(o.ref):"tag"===o.$tag&&s.addTag(o.k,o.v)}),e.on("<osm.relation>",e=>new L.Relation(e.id,l)),e.on("</osm.relation.member>",(e,t)=>{var t=l.get("relation/"+(null==t?void 0:t.id)),r={type:e.type,role:e.role||"",ref:e.ref};if(e.lat&&e.lon){r.lat=e.lat,r.lon=e.lon,r.tags={};for(var[s,o]of Object.entries(e))!s.startsWith("$")&&["type","lat","lon"].indexOf(s)<0&&(r[s]=o)}if(e.$innerNodes){var i,n=[],a=[];for(i of e.$innerNodes)i.lat&&i.lon?n.push(i):i.ref&&a.push(i.ref);0<n.length?r.geometry=n:0<a.length&&(r.nodes=a)}t.addMember(r)}),e.on("</osm.relation.bounds>",(e,t)=>{l.get("relation/"+(null==t?void 0:t.id)).setBounds([parseFloat(e.minlon),parseFloat(e.minlat),parseFloat(e.maxlon),parseFloat(e.maxlat)])}),e.on("</osm.relation.tag>",(e,t)=>{l.get("relation/"+(null==t?void 0:t.id)).addTag(e.k,e.v)}),e.parse(t));a.bindAll();for(n of a.values())if(!(0<n.refCount)||n.hasTag&&s&&!(n instanceof x.Way&&o)){var m=n.toFeatureArray();if(n instanceof L.Relation&&!r&&0<m.length)return m[0].geometry;d=d.concat(m)}return{type:"FeatureCollection",features:d}}},{"./node":3,"./ref-elements":6,"./relation":7,"./utils":8,"./way":10,"./xmlparser":11}],2:[function(e,t,r){Object.defineProperty(r,"__esModule",{value:!0}),r.LateBinder=void 0;r.LateBinder=class{constructor(e,t,r,s){this.container=e,this.valueFunc=t,this.ctx=r,this.args=s}bind(){var e=this.valueFunc.apply(this.ctx,this.args),t=this.container.indexOf(this);t<0||(t=[t,1],e&&t.push(e),Array.prototype.splice.apply(this.container,t))}}},{}],3:[function(e,t,r){Object.defineProperty(r,"__esModule",{value:!0}),r.Node=void 0;var s=e("./osm-object");let o=e("./utils");class i extends s.OsmObject{constructor(e,t){super("node",e,t)}setLatLng(e){this.latLng=e}toFeatureArray(){return this.latLng?[{type:"Feature",id:this.getCompositeId(),properties:this.getProps(),geometry:{type:"Point",coordinates:(0,o.strArrayToFloat)([this.latLng.lon,this.latLng.lat])}}]:[]}getLatLng(){return this.latLng}}r.Node=i},{"./osm-object":4,"./utils":8}],4:[function(e,t,r){Object.defineProperty(r,"__esModule",{value:!0}),r.OsmObject=void 0;r.OsmObject=class{constructor(e,t,r){this.type=e,this.id=t,this.refElems=r,this.tags={},this.props={id:this.getCompositeId()},this.refCount=0,this.hasTag=!1,r&&r.add(this.getCompositeId(),this)}addTags(e){this.tags=Object.assign(this.tags,e),this.hasTag=!0}addTag(e,t){this.tags[e]=t,this.hasTag=!0}addProp(e,t){this.props[e]=t}addProps(e){this.props=Object.assign(this.props,e)}getCompositeId(){return this.type+"/"+this.id}getProps(){return Object.assign(this.props,this.tags)}}},{}],5:[function(e,t,r){t.exports={building:{},highway:{whitelist:["services","rest_area","escape","elevator"]},natural:{blacklist:["coastline","cliff","ridge","arete","tree_row"]},landuse:{},waterway:{whitelist:["riverbank","dock","boatyard","dam"]},amenity:{},leisure:{},barrier:{whitelist:["city_wall","ditch","hedge","retaining_wall","wall","spikes"]},railway:{whitelist:["station","turntable","roundhouse","platform"]},area:{},boundary:{},man_made:{blacklist:["cutline","embankment","pipeline"]},power:{whitelist:["plant","substation","generator","transformer"]},place:{},shop:{},aeroway:{blacklist:["taxiway"]},tourism:{},historic:{},public_transport:{},office:{},"building:part":{},military:{},ruins:{},"area:highway":{},craft:{},golf:{},indoor:{}}},{}],6:[function(e,t,r){Object.defineProperty(r,"__esModule",{value:!0}),r.RefElements=void 0;class s extends Map{constructor(){super(),this.binders=[]}add(e,t){this.set(e,t)}addBinder(e){this.binders.push(e)}bindAll(){this.binders.forEach(e=>e.bind())}}r.RefElements=s},{}],7:[function(e,t,r){Object.defineProperty(r,"__esModule",{value:!0}),r.Relation=void 0;var s=e("./osm-object");let a=e("./way"),l=e("./node"),g=e("./way-collection"),d=e("./late-binder"),n=e("./utils");class o extends s.OsmObject{constructor(e,t){super("relation",e,t),this.relations=[],this.nodes=[],this.bounds=void 0,this.ways=[],this.roles=[]}setBounds(e){this.bounds=e}addMember(e){switch(e.type){case"relation":var t=new d.LateBinder(this.relations,e=>{e=this.refElems.get("relation/"+e);if(e)return e.refCount++,e},this,[e.ref]);this.relations.push(t),this.refElems.addBinder(t);break;case"way":if(e.role||(e.role=""),e.geometry){t=new a.Way(e.ref,this.refElems);t.setLatLngArray(e.geometry),t.refCount++,this.ways.push(t),this.roles.push(e.role)}else if(e.nodes){var r,s=new a.Way(e.ref,this.refElems);for(r of e.nodes)s.addNodeRef(r);s.refCount++,this.ways.push(s),this.roles.push(e.role)}else{t=new d.LateBinder(this.ways,e=>{e=this.refElems.get("way/"+e);if(e)return e.refCount++,e},this,[e.ref]);this.ways.push(t),this.roles.push(e.role),this.refElems.addBinder(t)}break;case"node":var o=null;if(e.lat&&e.lon){(o=new l.Node(e.ref,this.refElems)).setLatLng({lon:e.lon,lat:e.lat}),e.tags&&o.addTags(e.tags);for(var[i,n]of Object.entries(e))["id","type","lat","lon"].indexOf(i)<0&&o.addProp(i,n);o.refCount++,this.nodes.push(o)}else{t=new d.LateBinder(this.nodes,e=>{e=this.refElems.get("node/"+e);if(e)return e.refCount++,e},this,[e.ref]);this.nodes.push(t),this.refElems.addBinder(t)}}}constructStringGeometry(e){e=e?e.mergeWays():[];return 0===e.length?null:{type:"MultiLineString",coordinates:e}}constructPolygonGeometry(e,t){var r=e?e.toRings("counterclockwise"):[],s=t?t.toRings("clockwise"):[];if(0<r.length){var o=[];let e;for(e of r)o.push([e]);for(e=s.shift();e;){for(var i in r)if((0,n.pointInsidePolygon)((0,n.first)(e),r[i])){o[i].push(e);break}e=s.shift()}return 1===o.length?{type:"Polygon",coordinates:o[0]}:{type:"MultiPolygon",coordinates:o}}return null}toFeatureArray(){var t,e=[],r=[];let s=[];for(t of this.relations)if(t)for(let e=0;e<t.ways.length;e++){var o=t.ways[e];this.ways.push(o),this.roles.push(t.roles[e])}var i,n={type:"Feature",id:this.getCompositeId(),bbox:this.bounds,properties:this.getProps(),geometry:null};if(this.bounds||delete n.bbox,this.roles.some(e=>"outer"===e)){var a=new g.WayCollection,l=new g.WayCollection;for(let e=0;e<this.ways.length;e++){var d=this.ways[e],u=this.roles[e];"outer"===u?a.addWay(d):"inner"===u&&l.addWay(d)}var h=Object.assign({},n),f=this.constructPolygonGeometry(a,l);f&&(h.geometry=f,e.push(h))}else{var c,p=new g.WayCollection;for(c of this.ways)p.addWay(c);f=this.constructStringGeometry(p);f&&((h=Object.assign({},n)).geometry=f,r.push(h))}for(i of this.nodes)s=s.concat(i.toFeatureArray());return[...e,...r,...s]}}r.Relation=o},{"./late-binder":2,"./node":3,"./osm-object":4,"./utils":8,"./way":10,"./way-collection":9}],8:[function(e,t,r){function s(e){return e[0]}function o(e){return e[e.length-1]}function i(e){return e.join(",")}function n(e){return e.map(parseFloat)}Object.defineProperty(r,"__esModule",{value:!0}),r.purgeProps=function(e,t){if(e){var r=Object.assign({},e);if(t)for(var s of t)delete r[s];return r}return{}},r.first=s,r.last=o,r.coordsToKey=i,r.addToMap=function(e,t,r){var s=e[t];s?s.push(r):e[t]=[r]},r.removeFromMap=function(e,t,r){let s=e[t],o=-1;s&&(o=s.indexOf(r));0<=o&&s.splice(o,1)},r.getFirstFromMap=function(e,t){e=e[t];if(e&&0<e.length)return e[0];return null},r.isRing=function(e){return 3<e.length&&i(e[0])===i(o(e))},r.ringDirection=function(s,o,e){o=o||0,e=e||1;var t=s.reduce((e,t,r)=>s[e][o||0]>t[o||0]?e:r,0),r=t<=0?s.length-2:t-1,i=t>=s.length-1?1:t+1,n=s[r][o],a=s[t][o],l=s[i][o],r=s[r][e],t=s[t][e],i=s[i][e],e=(a-n)*(i-r)-(l-n)*(t-r);return e<0?"clockwise":"counterclockwise"},r.pointInsidePolygon=function(r,s,o,i){o=o||0,i=i||1;let n=!1;for(let e=0,t=s.length-1;e<s.length;t=e++)(s[e][o]<=r[o]&&r[o]<s[t][o]||s[t][o]<=r[o]&&r[o]<s[e][o])&&r[i]<(s[t][i]-s[e][i])*(r[o]-s[e][o])/(s[t][o]-s[e][o])+s[e][i]&&(n=!n);return n},r.strArrayArrayToFloat=function(e){return e.map(n)},r.strArrayToFloat=n},{}],9:[function(e,t,r){Object.defineProperty(r,"__esModule",{value:!0}),r.WayCollection=void 0;let i=e("./utils");class s extends Array{constructor(){super(),this.firstMap={},this.lastMap={}}addWay(e){e=e.toCoordsArray();0<e.length&&(this.push(e),(0,i.addToMap)(this.firstMap,(0,i.coordsToKey)((0,i.first)(e)),e),(0,i.addToMap)(this.lastMap,(0,i.coordsToKey)((0,i.last)(e)),e))}mergeWays(){var r=[];let s=this.shift();for(;s;){(0,i.removeFromMap)(this.firstMap,(0,i.coordsToKey)((0,i.first)(s)),s),(0,i.removeFromMap)(this.lastMap,(0,i.coordsToKey)((0,i.last)(s)),s);let e=s,t;do{var o=this.getNextWay(e),o=(t=o.next,o.mergeType);if(t)switch(this.splice(this.indexOf(t),1),(0,i.removeFromMap)(this.firstMap,(0,i.coordsToKey)((0,i.first)(t)),t),(0,i.removeFromMap)(this.lastMap,(0,i.coordsToKey)((0,i.last)(t)),t),o){case 0:e=e.concat(t.slice(1));break;case 1:t.reverse(),e=e.concat(t.slice(1));break;case 2:e.reverse(),e=e.concat(t.slice(1));break;case 3:e=t.concat(e.slice(1))}}while(t);r.push((0,i.strArrayArrayToFloat)(e)),s=this.shift()}return r}getNextWay(e){var t=(0,i.coordsToKey)((0,i.last)(e)),e=(0,i.coordsToKey)((0,i.first)(e)),r=0<this.length?this[0]:null;if(r){var s=(0,i.coordsToKey)((0,i.first)(r)),o=(0,i.coordsToKey)((0,i.last)(r));if(t===s)return{next:r,mergeType:0};if(t===o)return{next:r,mergeType:1};if(e===s)return{next:r,mergeType:2};if(e===o)return{next:r,mergeType:3}}return(r=(0,i.getFirstFromMap)(this.firstMap,t))?{next:r,mergeType:0}:{next:(0,i.getFirstFromMap)(this.lastMap,t),mergeType:1}}toRings(e){var t=this.mergeWays(),r=[];let s=t.shift();for(;s;)(0,i.isRing)(s)&&((0,i.ringDirection)(s)!==e&&s.reverse(),r.push(s)),s=t.shift();return r}}r.WayCollection=s},{"./utils":8}],10:[function(e,t,r){var s=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}},o=(Object.defineProperty(r,"__esModule",{value:!0}),r.Way=void 0,e("./osm-object"));let i=e("./late-binder"),n=e("./utils"),a=s(e("./polytags.json"));class l extends o.OsmObject{constructor(e,t){super("way",e,t),this.latLngArray=[],this.isPolygon=!1}addLatLng(e){this.latLngArray.push(e)}setLatLngArray(e){this.latLngArray=e}addNodeRef(e){e=new i.LateBinder(this.latLngArray,e=>{e=this.refElems.get("node/"+e);if(e)return e.refCount++,e.getLatLng()},this,[e]);this.latLngArray.push(e),this.refElems.addBinder(e)}addTags(e){super.addTags(e);for(var[t,r]of Object.entries(e))this.analyzeTag(t,r)}addTag(e,t){super.addTag(e,t),this.analyzeTag(e,t)}toCoordsArray(){return this.latLngArray.map(e=>[e.lon,e.lat])}toFeatureArray(){var e,t=this.toCoordsArray();return 1<t.length?(t=(0,n.strArrayArrayToFloat)(t),e={type:"Feature",id:this.getCompositeId(),properties:this.getProps(),geometry:{type:"LineString",coordinates:t}},this.isPolygon&&(0,n.isRing)(t)&&("counterclockwise"!==(0,n.ringDirection)(t)&&t.reverse(),e.geometry={type:"Polygon",coordinates:[t]}),[e]):[]}analyzeTag(e,t){e=a.default[e];e&&(this.isPolygon=!0,e.whitelist?this.isPolygon=0<=e.whitelist.indexOf(t):e.blacklist&&(this.isPolygon=!(0<=e.blacklist.indexOf(t))))}}r.Way=l},{"./late-binder":2,"./osm-object":4,"./polytags.json":5,"./utils":8}],11:[function(e,t,r){function o(e){return null!==e.match(/^(.+?)\[(.+?)\]>$/g)}function i(e){var t=/^(.+?)\[(.+?)\]>$/g.exec(e);return t?{evt:t[1]+">",exp:t[2]}:{evt:e}}Object.defineProperty(r,"__esModule",{value:!0}),r.XmlParser=void 0;class s{constructor(e){this.queryParent=!1,this.progressive=!1,this.parentMap=new WeakMap,e&&(this.queryParent=!!e.queryParent,this.progressive=e.progressive,this.queryParent)&&(this.parentMap=new WeakMap),this.evtListeners={}}parse(s,o,i){i=i?i+".":"";var n=/<([^ >\/]+)(.*?)>/gm,a=[];let l=n.exec(s);for(;l;){var d=l[1],u={$tag:d},h=i+d,f=l[2].trim();let e=!1;(f.endsWith("/")||d.startsWith("?")||d.startsWith("!"))&&(e=!0);var c,p=/([^ ]+?)="(.+?)"/g,g=/([^ ]+?)='(.+?)'/g;let t=p.exec(f),r=!1;for(;t;)r=!0,u[t[1]]=t[2],t=p.exec(f);if(!r)for(t=g.exec(f);t;)r=!0,u[t[1]]=t[2],t=g.exec(f);r||""===f||(u.text=f),this.progressive&&this.emit(`<${h}>`,u,o),e||((d=new RegExp(`([^]+?)</${d}>`,"g")).lastIndex=n.lastIndex,(c=d.exec(s))&&c[1]&&(n.lastIndex=d.lastIndex,0<(d=this.parse(c[1],u,h)).length?u.$innerNodes=d:u.$innerText=c[1])),this.queryParent&&o&&this.parentMap.set(u,o),this.progressive&&this.emit(`</${h}>`,u,o),a.push(u),l=n.exec(s)}return a}getParent(e){return this.queryParent?this.parentMap.get(e):null}addListener(e,t){var r,s;o(e)&&((r=i(e)).exp&&(t.condition=(s="return "+(s=r.exp).replace(/(\$.+?)(?=[=!.])/g,"node.$&")+";",new Function("node",s))),e=r.evt),this.$addListener(e,t)}removeListener(e,t){o(e)&&(e=i(e).evt),this.$removeListener(e,t)}on(e,t){this.addListener(e,t)}off(e,t){this.removeListener(e,t)}$addListener(e,t){var r=this.evtListeners[e];r?r.push(t):this.evtListeners[e]=[t]}$removeListener(e,t){e=this.evtListeners[e];let r=-1;0<=(r=e?e.indexOf(t):r)&&e.splice(r,1)}emit(e,...t){e=this.evtListeners[e];if(e)for(var r of e)(!r.condition||!0===r.condition.apply(null,t))&&r.apply(null,t)}}r.XmlParser=s},{}]},{},[1])(1)});
|
package/package.json
CHANGED
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"polygon",
|
|
45
45
|
"multipolygon"
|
|
46
46
|
],
|
|
47
|
-
"license": "
|
|
47
|
+
"license": "MIT",
|
|
48
48
|
"main": "dist/node/index.js",
|
|
49
49
|
"types": "dist/node/index.d.ts",
|
|
50
50
|
"name": "osm2geojson-lite",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"optionalDependencies": {
|
|
62
62
|
"@types/geojson": "^7946.0.16"
|
|
63
63
|
},
|
|
64
|
-
"version": "1.1.
|
|
64
|
+
"version": "1.1.2",
|
|
65
65
|
"directories": {
|
|
66
66
|
"lib": "lib",
|
|
67
67
|
"test": "test"
|