forked from perliedman/geojson-path-finder
-
Notifications
You must be signed in to change notification settings - Fork 1
/
compactor.js
130 lines (109 loc) · 4.23 KB
/
compactor.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
126
127
128
129
130
'use strict';
module.exports = {
compactNode: compactNode,
compactGraph: compactGraph
};
function findNextEnd(prev, v, vertices, ends, vertexCoords, edgeData, trackIncoming, options) {
var weight = vertices[prev][v],
reverseWeight = vertices[v][prev],
coordinates = [],
path = [],
reducedEdge = options.edgeDataSeed;
if (options.edgeDataReduceFn) {
reducedEdge = options.edgeDataReduceFn(reducedEdge, edgeData[v][prev]);
}
while (!ends[v]) {
var edges = vertices[v];
if (!edges) { break; }
// first neighbour
var next = Object.keys(edges).filter(function notPrevious(k) { return k !== prev; })[0];
weight += edges[next];
if (trackIncoming) {
reverseWeight += vertices[next][v];
if (path.indexOf(v) >= 0) {
ends[v] = vertices[v];
break;
}
path.push(v);
}
if (options.edgeDataReduceFn) {
reducedEdge = options.edgeDataReduceFn(reducedEdge, edgeData[v][next]);
}
coordinates.push(vertexCoords[v]);
prev = v;
v = next;
}
return {
vertex: v,
weight: weight,
reverseWeight: reverseWeight,
coordinates: coordinates,
reducedEdge: reducedEdge
};
}
function compactNode(k, vertices, ends, vertexCoords, edgeData, trackIncoming, options) {
options = options || {};
var neighbors = vertices[k];
return Object.keys(neighbors).reduce(function compactEdge(result, j) {
var neighbor = findNextEnd(k, j, vertices, ends, vertexCoords, edgeData, trackIncoming, options);
var weight = neighbor.weight;
var reverseWeight = neighbor.reverseWeight;
if (neighbor.vertex !== k) {
if (!result.edges[neighbor.vertex] || result.edges[neighbor.vertex] > weight) {
result.edges[neighbor.vertex] = weight;
result.coordinates[neighbor.vertex] = [vertexCoords[k]].concat(neighbor.coordinates);
result.reducedEdges[neighbor.vertex] = neighbor.reducedEdge;
}
if (trackIncoming &&
!isNaN(reverseWeight) && (!result.incomingEdges[neighbor.vertex] || result.incomingEdges[neighbor.vertex] > reverseWeight)) {
result.incomingEdges[neighbor.vertex] = reverseWeight;
var coordinates = [vertexCoords[k]].concat(neighbor.coordinates);
coordinates.reverse();
result.incomingCoordinates[neighbor.vertex] = coordinates;
}
}
return result;
}, {edges: {}, incomingEdges: {}, coordinates: {}, incomingCoordinates: {}, reducedEdges: {}});
}
function compactGraph(vertices, vertexCoords, edgeData, options) {
options = options || {};
var progress = options.progress;
// find end nodes
var ends = Object.keys(vertices).reduce(function findEnds(es, k, i, vs) {
var vertex = vertices[k];
var edges = Object.keys(vertex);
var numberEdges = edges.length;
var remove;
if (options.compact !== undefined && !options.compact) {
remove = false;
} else if (numberEdges === 1) {
var other = vertices[edges[0]];
remove = !other[k];
} else if (numberEdges === 2) {
remove = edges.filter(function(n) {
return vertices[n][k];
}).length === numberEdges;
} else {
remove = false;
}
if (!remove) {
es[k] = vertex;
}
if (i % 1000 === 0 && progress) {
progress('compact:ends', i, vs.length);
}
return es;
}, {});
return Object.keys(ends).reduce(function compactEnd(result, k, i, es) {
var compacted = compactNode(k, vertices, ends, vertexCoords, edgeData, false, options);
result.graph[k] = compacted.edges;
result.coordinates[k] = compacted.coordinates;
if (options.edgeDataReduceFn) {
result.reducedEdges[k] = compacted.reducedEdges;
}
if (i % 1000 === 0 && progress) {
progress('compact:nodes', i, es.length);
}
return result;
}, {graph: {}, coordinates: {}, reducedEdges: {}});
};