2
2
3
3
import com .conveyal .r5 .analyst .StreetTimesAndModes ;
4
4
import com .conveyal .r5 .transit .TransitLayer ;
5
+ import com .conveyal .r5 .transit .TripPattern ;
5
6
import com .conveyal .r5 .transit .path .Path ;
6
7
import com .conveyal .r5 .transit .path .PatternSequence ;
7
8
import com .conveyal .r5 .transit .path .RouteSequence ;
8
9
import com .google .common .collect .HashMultimap ;
9
10
import com .google .common .collect .Multimap ;
10
11
import gnu .trove .list .TIntList ;
11
12
import gnu .trove .list .array .TIntArrayList ;
13
+ import gnu .trove .set .TIntSet ;
14
+ import gnu .trove .set .hash .TIntHashSet ;
12
15
import org .apache .commons .lang3 .ArrayUtils ;
16
+ import org .slf4j .Logger ;
17
+ import org .slf4j .LoggerFactory ;
13
18
19
+ import java .awt .*;
20
+ import java .lang .invoke .MethodHandles ;
14
21
import java .util .ArrayList ;
22
+ import java .util .Arrays ;
15
23
import java .util .Collection ;
16
24
import java .util .Comparator ;
17
25
import java .util .List ;
32
40
33
41
public class PathResult {
34
42
43
+ private static final Logger LOG = LoggerFactory .getLogger (MethodHandles .lookup ().lookupClass ());
44
+
35
45
/**
36
46
* The maximum number of destinations for which we'll generate detailed path information in a single request.
37
47
* Detailed path information was added on to the original design, which returned a simple grid of travel times.
@@ -41,12 +51,14 @@ public class PathResult {
41
51
public static final int MAX_PATH_DESTINATIONS = 5_000 ;
42
52
43
53
private final int nDestinations ;
54
+
44
55
/**
45
56
* Array with one entry per destination. Each entry is a map from a "path template" to the associated iteration
46
57
* details. For now, the path template is a route-based path ignoring per-iteration details such as wait time.
47
58
* With additional changes, patterns could be collapsed further to route combinations or modes.
48
59
*/
49
60
public final Multimap <RouteSequence , Iteration >[] iterationsForPathTemplates ;
61
+
50
62
private final TransitLayer transitLayer ;
51
63
52
64
public static final String [] DATA_COLUMNS = new String []{
@@ -83,6 +95,15 @@ public PathResult(AnalysisWorkerTask task, TransitLayer transitLayer) {
83
95
* pattern-based keys
84
96
*/
85
97
public void setTarget (int targetIndex , Multimap <PatternSequence , Iteration > patterns ) {
98
+
99
+ // When selected link analysis is enabled, filter down the PatternSequence-Iteration Multimap to retain only
100
+ // those keys passing through the selected links.
101
+ // TODO Maybe selectedLink should be on TransitLayer, and somehow indicate the number of removed iterations.
102
+ if (transitLayer .parentNetwork .selectedLink != null ) {
103
+ patterns = transitLayer .parentNetwork .selectedLink .filterPatterns (patterns );
104
+ }
105
+
106
+ // The rest of this runs independent of whether a SelectedLink filtered down the patterns-iterations map.
86
107
Multimap <RouteSequence , Iteration > routes = HashMultimap .create ();
87
108
patterns .forEach (((patternSeq , iteration ) -> routes .put (new RouteSequence (patternSeq , transitLayer ), iteration )));
88
109
iterationsForPathTemplates [targetIndex ] = routes ;
@@ -103,6 +124,35 @@ public ArrayList<String[]>[] summarizeIterations(Stat stat) {
103
124
summary [d ] = new ArrayList <>();
104
125
Multimap <RouteSequence , Iteration > iterationMap = iterationsForPathTemplates [d ];
105
126
if (iterationMap != null ) {
127
+ // SelectedLink case: collapse all RouteSequences and Iterations for this OD pair into one to simplify.
128
+ // This could also be done by merging all Iterations under a single RouteSequence with all route IDs.
129
+ if (transitLayer .parentNetwork .selectedLink != null ) {
130
+ int nIterations = 0 ;
131
+ TIntSet allRouteIds = new TIntHashSet ();
132
+ double summedTotalTime = 0 ;
133
+ for (RouteSequence routeSequence : iterationMap .keySet ()) {
134
+ Collection <Iteration > iterations = iterationMap .get (routeSequence );
135
+ nIterations += iterations .size ();
136
+ allRouteIds .addAll (routeSequence .routes );
137
+ summedTotalTime += iterations .stream ().mapToInt (i -> i .totalTime ).sum ();
138
+ }
139
+ // Many destinations will have no iterations at all passing through the SelectedLink area.
140
+ // Skip those to keep the CSV output short.
141
+ if (nIterations > 0 ) {
142
+ String [] row = new String [DATA_COLUMNS .length ];
143
+ Arrays .fill (row , "ALL" );
144
+ String allRouteIdsPipeSeparated = Arrays .stream (allRouteIds .toArray ())
145
+ .mapToObj (transitLayer .routes ::get )
146
+ .map (routeInfo -> routeInfo .route_id )
147
+ .collect (Collectors .joining ("|" ));
148
+ row [0 ] = allRouteIdsPipeSeparated ;
149
+ row [row .length - 1 ] = Integer .toString (nIterations );
150
+ row [row .length - 2 ] = String .format ("%.1f" , summedTotalTime / nIterations / 60d ); // Average total time
151
+ summary [d ].add (row );
152
+ }
153
+ continue ;
154
+ }
155
+ // Standard (non SelectedLink) case.
106
156
for (RouteSequence routeSequence : iterationMap .keySet ()) {
107
157
Collection <Iteration > iterations = iterationMap .get (routeSequence );
108
158
int nIterations = iterations .size ();
0 commit comments