23
23
* implementation NOT thread-safe.
24
24
*
25
25
* @author mrieser / Simunto, sponsored by SBB Swiss Federal Railways
26
+ * @author hrewald, nkuehnel / MOIA turn restriction adjustments
26
27
*/
27
28
public class LeastCostPathTree {
28
29
@@ -31,6 +32,8 @@ public class LeastCostPathTree {
31
32
private final TravelDisutility td ;
32
33
private final double [] data ; // 3 entries per node: time, cost, distance
33
34
private final int [] comingFrom ;
35
+ private final int [] fromLink ;
36
+ private final int [] comingFromLink ;
34
37
private final SpeedyGraph .LinkIterator outLI ;
35
38
private final SpeedyGraph .LinkIterator inLI ;
36
39
private final NodeMinHeap pq ;
@@ -41,6 +44,8 @@ public LeastCostPathTree(SpeedyGraph graph, TravelTime tt, TravelDisutility td)
41
44
this .td = td ;
42
45
this .data = new double [graph .nodeCount * 3 ];
43
46
this .comingFrom = new int [graph .nodeCount ];
47
+ this .fromLink = new int [graph .nodeCount ];
48
+ this .comingFromLink = new int [graph .linkCount ];
44
49
this .pq = new NodeMinHeap (graph .nodeCount , this ::getCost , this ::setCost );
45
50
this .outLI = graph .getOutLinkIterator ();
46
51
this .inLI = graph .getInLinkIterator ();
@@ -53,6 +58,7 @@ public void calculate(int startNode, double startTime, Person person, Vehicle ve
53
58
public void calculate (int startNode , double startTime , Person person , Vehicle vehicle , StopCriterion stopCriterion ) {
54
59
Arrays .fill (this .data , Double .POSITIVE_INFINITY );
55
60
Arrays .fill (this .comingFrom , -1 );
61
+ Arrays .fill (this .fromLink , -1 );
56
62
57
63
setData (startNode , 0 , startTime , 0 );
58
64
@@ -86,18 +92,32 @@ public void calculate(int startNode, double startTime, Person person, Vehicle ve
86
92
this .pq .decreaseKey (toNode , newCost );
87
93
setData (toNode , newCost , newTime , currDistance + link .getLength ());
88
94
this .comingFrom [toNode ] = nodeIdx ;
95
+ this .fromLink [toNode ] = linkIdx ;
89
96
}
90
97
} else {
91
98
setData (toNode , newCost , newTime , currDistance + link .getLength ());
92
99
this .pq .insert (toNode );
93
100
this .comingFrom [toNode ] = nodeIdx ;
101
+ this .fromLink [toNode ] = linkIdx ;
94
102
}
95
103
}
96
104
}
97
105
98
106
if (graph .hasTurnRestrictions ()) {
99
107
consolidateColoredNodes ();
100
108
}
109
+
110
+ Arrays .fill (this .comingFromLink , -1 );
111
+ for (int i = 0 ; i < graph .nodeCount ; i ++) {
112
+ Node node = graph .getNode (i );
113
+ if (node != null ) {
114
+ this .outLI .reset (i );
115
+ while (this .outLI .next ()) {
116
+ int previousLinkIdx = fromLink [i ];
117
+ this .comingFromLink [outLI .getLinkIndex ()] = previousLinkIdx ;
118
+ }
119
+ }
120
+ }
101
121
}
102
122
103
123
public void calculateBackwards (int arrivalNode , double arrivalTime , Person person , Vehicle vehicle ) {
@@ -107,6 +127,7 @@ public void calculateBackwards(int arrivalNode, double arrivalTime, Person perso
107
127
public void calculateBackwards (int arrivalNode , double arrivalTime , Person person , Vehicle vehicle , StopCriterion stopCriterion ) {
108
128
Arrays .fill (this .data , Double .POSITIVE_INFINITY );
109
129
Arrays .fill (this .comingFrom , -1 );
130
+ Arrays .fill (this .fromLink , -1 );
110
131
111
132
setData (arrivalNode , 0 , arrivalTime , 0 );
112
133
@@ -140,18 +161,32 @@ public void calculateBackwards(int arrivalNode, double arrivalTime, Person perso
140
161
this .pq .decreaseKey (fromNode , newCost );
141
162
setData (fromNode , newCost , newTime , currDistance + link .getLength ());
142
163
this .comingFrom [fromNode ] = nodeIdx ;
164
+ this .fromLink [fromNode ] = linkIdx ;
143
165
}
144
166
} else {
145
167
setData (fromNode , newCost , newTime , currDistance + link .getLength ());
146
168
this .pq .insert (fromNode );
147
169
this .comingFrom [fromNode ] = nodeIdx ;
170
+ this .fromLink [fromNode ] = linkIdx ;
148
171
}
149
172
}
150
173
}
151
174
152
175
if (graph .hasTurnRestrictions ()) {
153
176
consolidateColoredNodes ();
154
177
}
178
+
179
+ Arrays .fill (this .comingFromLink , -1 );
180
+ for (int i = 0 ; i < graph .nodeCount ; i ++) {
181
+ Node node = graph .getNode (i );
182
+ if (node != null ) {
183
+ this .inLI .reset (i );
184
+ while (this .inLI .next ()) {
185
+ int previousLinkIdx = fromLink [i ];
186
+ this .comingFromLink [inLI .getLinkIndex ()] = previousLinkIdx ;
187
+ }
188
+ }
189
+ }
155
190
}
156
191
157
192
private void consolidateColoredNodes () {
@@ -169,6 +204,7 @@ private void consolidateColoredNodes() {
169
204
if (coloredCost < uncoloredCost ) {
170
205
setData (uncoloredIndex , coloredCost , getTimeRaw (i ), getDistance (i ));
171
206
this .comingFrom [uncoloredIndex ] = this .comingFrom [i ];
207
+ this .fromLink [uncoloredIndex ] = this .fromLink [i ];
172
208
}
173
209
}
174
210
}
@@ -206,10 +242,14 @@ private void setData(int nodeIndex, double cost, double time, double distance) {
206
242
this .data [index + 2 ] = distance ;
207
243
}
208
244
209
- public PathIterator getComingFromIterator (Node node ) {
245
+ public PathIterator getNodePathIterator (Node node ) {
210
246
return new PathIterator (node );
211
247
}
212
248
249
+ public LinkPathIterator getLinkPathIterator (Node node ) {
250
+ return new LinkPathIterator (node );
251
+ }
252
+
213
253
public interface StopCriterion {
214
254
215
255
boolean stop (int nodeIndex , double arrivalTime , double travelCost , double distance , double departureTime );
@@ -253,7 +293,7 @@ public PathIterator(Node startNode) {
253
293
}
254
294
255
295
@ Override
256
- public Node next () throws NoSuchElementException {
296
+ public Node next () {
257
297
current = comingFrom [current ];
258
298
if (current < 0 ) {
259
299
throw new NoSuchElementException ();
@@ -266,4 +306,34 @@ public boolean hasNext() {
266
306
return comingFrom [current ] >= 0 ;
267
307
}
268
308
}
309
+
310
+ // by not exposing internal indices to the outside we ensure that only uncolored nodes are returned. nkuehnel Feb'25
311
+ public final class LinkPathIterator implements Iterator <Link > {
312
+
313
+ private boolean firstStep = true ;
314
+
315
+ private int current ;
316
+
317
+ public LinkPathIterator (Node startNode ) {
318
+ current = fromLink [startNode .getId ().index ()];
319
+ }
320
+
321
+ @ Override
322
+ public Link next () {
323
+ if (firstStep ) {
324
+ firstStep = false ;
325
+ return graph .getLink (current );
326
+ }
327
+ current = comingFromLink [current ];
328
+ if (current < 0 ) {
329
+ throw new NoSuchElementException ();
330
+ }
331
+ return graph .getLink (current );
332
+ }
333
+
334
+ @ Override
335
+ public boolean hasNext () {
336
+ return current >= 0 && (comingFromLink [current ] >= 0 || firstStep );
337
+ }
338
+ }
269
339
}
0 commit comments