-
Notifications
You must be signed in to change notification settings - Fork 149
/
geojson-utils.js
125 lines (105 loc) · 3.01 KB
/
geojson-utils.js
1
2
3
4
5
6
7
8
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
57
58
59
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
89
90
91
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
const {
cloneDeep,
filter,
groupBy,
last,
omit,
sortBy,
omitBy
} = require('lodash');
const { feature, featureCollection } = require('@turf/helpers');
function isValidLineString(lineString) {
if (!lineString) {
return false;
}
if (lineString.length <= 1) {
return false;
}
// Reject linestrings with two identical points
if (lineString.length === 2 && lineString[0][0] === lineString[1][0] && lineString[0][1] === lineString[1][1]) {
return false;
}
return true;
}
function consolidateShapes(shapes) {
const keys = new Set();
/* eslint-disable unicorn/no-array-reduce */
const segmentsArray = shapes.map(shape => shape.reduce((memo, point, idx) => {
if (idx > 0) {
memo.push([
[
shape[idx - 1].shape_pt_lon,
shape[idx - 1].shape_pt_lat
],
[
point.shape_pt_lon,
point.shape_pt_lat
]
]);
}
return memo;
}, []));
/* eslint-enable unicorn/no-array-reduce */
const consolidatedLineStrings = [];
for (const segments of segmentsArray) {
consolidatedLineStrings.push([]);
for (const segment of segments) {
const key1 = `${segment[0][0]},${segment[0][1]},${segment[1][0]},${segment[1][1]}`;
const key2 = `${segment[1][0]},${segment[1][1]},${segment[0][0]},${segment[0][1]}`;
const currentLine = last(consolidatedLineStrings);
if (keys.has(key1) || keys.has(key2)) {
consolidatedLineStrings.push([]);
} else {
// If its the first segment in a linestring, add both points
if (currentLine.length === 0) {
currentLine.push(segment[0]);
}
currentLine.push(segment[1]);
keys.add(key1);
keys.add(key2);
}
}
}
return filter(consolidatedLineStrings, isValidLineString);
}
function formatHexColor(color) {
if (color === null || color === undefined) {
return;
}
return `#${color}`;
}
function formatProperties(properties) {
const formattedProperties = {
...cloneDeep(omitBy(properties, value => value === null)),
route_color: formatHexColor(properties.route_color),
route_text_color: formatHexColor(properties.route_text_color)
};
if (properties.routes) {
formattedProperties.routes = properties.routes.map(route => formatProperties(route));
}
return formattedProperties;
}
exports.shapesToGeoJSONFeatures = (shapes, properties = {}) => {
const shapeGroups = Object.values(groupBy(shapes, 'shape_id')).map(shapeGroup => sortBy(shapeGroup, 'shape_pt_sequence'));
const lineStrings = consolidateShapes(shapeGroups);
return lineStrings.map(lineString => feature(
{
type: 'LineString',
coordinates: lineString
},
formatProperties(properties)
));
};
exports.stopsToGeoJSON = stops => {
const features = stops.map(stop => feature(
{
type: 'Point',
coordinates: [
stop.stop_lon,
stop.stop_lat
]
},
formatProperties(omit(stop, ['stop_lat', 'stop_lon']))
));
return featureCollection(features);
};