Skip to content

Commit c01333f

Browse files
committed
wip: try adding connections instead of manual annotations
However, connections are broken: 1. Whenever there are mutlitple trips combining into running on all related days, they are not found as they do not pass the equality check on having identical DaysOfOperation, leaving the `Single` call without matching elements. 2. Having two trips on different days on the same route and time with different connections works in the existing system. However, when collapsing trips to fix point 1 those two would be collapsed as well, breaking everything. 3. Grouping by all the stuff except for DaysOfOperation currently does not work as value equality collections have not yet been implemented. Conclusion: Value equality collections (Ronto4/R4Utils#11) need to be incorporated first. Then, grouping can be applied, solving this issue at its root. With some luck this might even make timetable views easier as some steps of collapsing will already have happened. [skip ci]
1 parent 0c5da62 commit c01333f

5 files changed

Lines changed: 161 additions & 39 deletions

File tree

Timetable/Line.cs

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,23 +65,67 @@ public required Route[] Routes
6565
/// Iterator over all <see cref="Line.Trip"/>s included in this <see cref="Line"/>.
6666
/// </summary>
6767
public IEnumerable<Trip> Trips => TripsCreate.Select(trip => new Trip
68-
{
69-
Line = this,
70-
Route = Routes[trip.RouteIndex],
71-
StartTime = trip.StartTime,
72-
TimeProfile = Routes[trip.RouteIndex].TimeProfiles[trip.TimeProfileIndex],
73-
DaysOfOperation = trip.DaysOfOperation,
74-
Annotations = trip.AnnotationSymbols
75-
.Select(symbol => new Trip.ManualAnnotation { Symbol = symbol, Text = Annotations[symbol] }).ToList(),
76-
Connections = trip.Connections,
77-
});
68+
{
69+
Line = this,
70+
Route = Routes[trip.RouteIndex],
71+
StartTime = trip.StartTime,
72+
TimeProfile = Routes[trip.RouteIndex].TimeProfiles[trip.TimeProfileIndex],
73+
DaysOfOperation = trip.DaysOfOperation,
74+
Annotations = trip.AnnotationSymbols
75+
.Select(symbol => new Trip.ManualAnnotation { Symbol = symbol, Text = Annotations[symbol] }).ToList(),
76+
Connections = trip.Connections,
77+
}).GroupBy(
78+
trip => (trip.Line, trip.Route, trip.StartTime, trip.TimeProfile, trip.Annotations, trip.Connections))
79+
.Select(group => new Trip
80+
{
81+
Line = group.Key.Line,
82+
Route = group.Key.Route,
83+
StartTime = group.Key.StartTime,
84+
TimeProfile = group.Key.TimeProfile,
85+
DaysOfOperation = group.Select(trip => trip.DaysOfOperation)
86+
.Aggregate(DaysOfOperation.None, (prev, next) => prev | next),
87+
Annotations = group.Key.Annotations,
88+
Connections = group.Key.Connections,
89+
});
7890

7991
/// <summary>
8092
/// Iterate over all <see cref="Line.Trip"/>s included in the <see cref="Line.Route"/> at index <c>routeIndex</c> in this <see cref="Line"/>.
8193
/// </summary>
8294
public IEnumerable<Trip> TripsOfRouteIndex(Index routeIndex) =>
8395
Trips.Where(trip => trip.Route == Routes[routeIndex]);
8496

97+
/// <summary>
98+
/// Determine whether there exists a trip of the given route, starting at the provided time, on all and only those days as specified.
99+
/// </summary>
100+
public bool HasTrip(Index ofRoute, TimeOnly startingAt, DaysOfOperation onDays) => TripsOfRouteIndex(ofRoute)
101+
.Where(trip => trip.StartTime == startingAt).Select(trip => trip.DaysOfOperation)
102+
.Aggregate(DaysOfOperation.None, (prev, next) => prev | next) == onDays;
103+
104+
/// <summary>
105+
/// Determine whether there exists a trip of the given route, starting at the provided time, on all and only those days as specified.
106+
/// </summary>
107+
public bool HasTrip(Index ofRoute, Func<Trip, TimeOnly> startingAt, TimeOnly startTimeComparer, DaysOfOperation onDays) => TripsOfRouteIndex(ofRoute)
108+
.Where(trip => startTimeComparer == startingAt(trip)).Select(trip => trip.DaysOfOperation)
109+
.Aggregate(DaysOfOperation.None, (prev, next) => prev | next) == onDays;
110+
111+
/// <summary>
112+
/// Get an arbitrary trip of the given route, starting at the provided time, if <see cref="HasTrip(System.Index,System.TimeOnly,Timetable.DaysOfOperation)"/> matches for the parameters.
113+
/// </summary>
114+
public Trip GetTrip(Index ofRoute, TimeOnly startingAt, DaysOfOperation onDays) =>
115+
HasTrip(ofRoute, startingAt, onDays)
116+
? TripsOfRouteIndex(ofRoute).First(trip => trip.StartTime == startingAt)
117+
: throw new InvalidOperationException(
118+
$"There is no matching trip in line {Name} for route index {ofRoute} and start time {startingAt}.");
119+
120+
/// <summary>
121+
/// Get an arbitrary trip of the given route, starting at the provided time, if <see cref="HasTrip(System.Index,System.TimeOnly,Timetable.DaysOfOperation)"/> matches for the parameters.
122+
/// </summary>
123+
public Trip GetTrip(Index ofRoute, Func<Trip, TimeOnly> startingAt, TimeOnly startTimeComparer, DaysOfOperation onDays) =>
124+
HasTrip(ofRoute, startingAt, startTimeComparer, onDays)
125+
? TripsOfRouteIndex(ofRoute).First(trip => startTimeComparer == startingAt(trip))
126+
: throw new InvalidOperationException(
127+
$"There is no matching trip in line {Name} for route index {ofRoute} and start time comparer {startTimeComparer}.");
128+
85129
/// <summary>
86130
/// All <see cref="TripCreate"/>s used to specify which <see cref="Line.Trip"/>s exist for this <see cref="Line"/>.
87131
/// </summary>

Timetable/Trip.cs

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,28 +42,49 @@ public partial record Trip
4242
/// <br/><br/>
4343
/// This should have 0 (no through service), 1 (start or end of through service), or 2 (middle of a through service) elements.
4444
/// </summary>
45-
public required List<TripCreate.Connection> Connections { private get; init; }
45+
/// <remarks>Prefer accessing through <see cref="GetConnections"/>, this property does not contain all relevant details.</remarks>
46+
public required List<TripCreate.Connection> Connections { internal get; init; }
4647

4748
/// <summary>
4849
/// Translate the trip-create <see cref="Timetable.Line.TripCreate.Connection"/>s present on this <see cref="Trip"/> into trip <see cref="Connection"/>s.
4950
/// </summary>
5051
/// <param name="allLines">All <see cref="Line"/>s present in the current network, indexed by their id.</param>
5152
// Consider adding more validation steps if it becomes a problem.
52-
public IEnumerable<Connection> GetConnections(IReadOnlyDictionary<string, Line> allLines) => Connections.Select(
53-
connection => new Connection
53+
public IEnumerable<Connection> GetConnections(IReadOnlyDictionary<string, Line> allLines)
54+
{
55+
try
56+
{
57+
return Connections.Select(
58+
connection => new Connection
59+
{
60+
Type = connection.Type,
61+
NotableViaStop = connection.NotableViaStop,
62+
Trip = connection.Type is ConnectionType.ContinuesAs
63+
? allLines[connection.ConnectingLineIdentifier].GetTrip(connection.ConnectingRouteIndex, TimeAtStop(Route.StopPositions.Length - 1).Add(connection.Delay), DaysOfOperation)
64+
// .TripsOfRouteIndex(connection.ConnectingRouteIndex)
65+
// .Single(trip =>
66+
// trip.StartTime ==
67+
// TimeAtStop(Route.StopPositions.Length - 1).Add(connection.Delay) &&
68+
// trip.DaysOfOperation == DaysOfOperation)
69+
: allLines[connection.ConnectingLineIdentifier].GetTrip(connection.ConnectingRouteIndex, trip => trip.TimeAtStop(trip.Route.StopPositions.Length - 1).Add(connection.Delay), StartTime, DaysOfOperation),
70+
// .TripsOfRouteIndex(connection.ConnectingRouteIndex)
71+
// .Single(trip =>
72+
// StartTime == trip.TimeAtStop(trip.Route.StopPositions.Length - 1)
73+
// .Add(connection.Delay) &&
74+
// trip.DaysOfOperation == DaysOfOperation),
75+
}).ToArray();
76+
}
77+
catch (InvalidOperationException ex)
5478
{
55-
Type = connection.Type,
56-
NotableViaStop = connection.NotableViaStop,
57-
Trip = connection.Type is ConnectionType.ContinuesAs
58-
? allLines[connection.ConnectingLineIdentifier].TripsOfRouteIndex(connection.ConnectingRouteIndex)
59-
.Single(trip =>
60-
trip.StartTime == TimeAtStop(Route.StopPositions.Length - 1).Add(connection.Delay) &&
61-
trip.DaysOfOperation == DaysOfOperation)
62-
: allLines[connection.ConnectingLineIdentifier].TripsOfRouteIndex(connection.ConnectingRouteIndex)
63-
.Single(trip =>
64-
StartTime == trip.TimeAtStop(trip.Route.StopPositions.Length - 1).Add(connection.Delay) &&
65-
trip.DaysOfOperation == DaysOfOperation),
66-
});
79+
Console.Error.WriteLine($"Error getting connections for trip {this} for connections {string.Join(", ", Connections)}");
80+
throw;
81+
}
82+
catch (Exception ex)
83+
{
84+
Console.Error.WriteLine($"Unknown error: {ex}");
85+
throw;
86+
}
87+
}
6788

6889
/// <summary>
6990
/// The time at which this <see cref="Trip"/> departs the <see cref="Stop"/> specified by the <see cref="Route"/>'s <see cref="Line.Route.CommonStopIndex"/>.

VipTimetable/Lines/Tram92/Tram92From20250110Until20250112.cs

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,28 @@ namespace VipTimetable.Lines.Tram92;
55

66
public class Tram92From20250110Until20250112 : ILineInstance
77
{
8+
private static Line.TripCreate.Connection ContinuesAs99(TimeSpan delay) => new Line.TripCreate.Connection
9+
{
10+
Delay = delay,
11+
Type = Line.Trip.ConnectionType.ContinuesAs,
12+
ConnectingLineIdentifier = "tram99",
13+
ConnectingRouteIndex = 7,
14+
};
15+
16+
private static Line.TripCreate.Connection ContinuesAs93(TimeSpan delay) => new Line.TripCreate.Connection
17+
{
18+
Delay = delay,
19+
Type = Line.Trip.ConnectionType.ContinuesAs,
20+
ConnectingLineIdentifier = "tram93",
21+
ConnectingRouteIndex = 11,
22+
};
23+
824
public DateOnly ValidFrom { get; } = new(2025, 1, 10);
925
public DateOnly? ValidUntilInclusive() => new(2025, 1, 12);
1026
private static Tram92From20241215 Original { get; } = new();
1127

1228
public Line Line { get; } = Original.Line with
1329
{
14-
Annotations = new Dictionary<string, string>
15-
{
16-
{ "A", "weiter als 99 nach Fontanestr." },
17-
{ "B", "weiter als 93 nach Glienicker Brücke." },
18-
},
1930
MainRouteIndices = [..Original.Line.MainRouteIndices, Original.Line.Routes.Length],
2031
Routes =
2132
[
@@ -96,7 +107,7 @@ trip with
96107
RouteIndex = Original.Line.Routes.Length /* Kirschallee -> Pl.d.Einh./W. */,
97108
TimeProfileIndex = 0,
98109
DaysOfOperation = trip.DaysOfOperation & DaysOfOperation.Weekend,
99-
AnnotationSymbols = ["A"],
110+
Connections = [ContinuesAs99(M2),],
100111
},
101112
];
102113
}
@@ -120,7 +131,17 @@ trip with
120131
RouteIndex = Original.Line.Routes.Length /* Kirschallee -> Pl.d.Einh./W. */,
121132
TimeProfileIndex = 0,
122133
DaysOfOperation = trip.DaysOfOperation & DaysOfOperation.Weekend,
123-
AnnotationSymbols = [trip.StartTime < new TimeOnly(19, 50) ? "B" : "A"],
134+
Connections =
135+
[
136+
trip.StartTime < new TimeOnly(19, 50)
137+
? ContinuesAs93(M4)
138+
: ContinuesAs99(trip.StartTime switch
139+
{
140+
_ when trip.StartTime == new TimeOnly(20, 5).AddMinutes(-12) => M0,
141+
_ when trip.StartTime == new TimeOnly(20, 25).AddMinutes(-12) => M5,
142+
_ => M2,
143+
})
144+
],
124145
}
125146
];
126147
}
@@ -132,17 +153,21 @@ trip with
132153
{
133154
RouteIndex = Original.Line.Routes.Length /* Kirschallee -> Pl.d.Einh./W. */,
134155
TimeProfileIndex = 0,
135-
DaysOfOperation = trip.DaysOfOperation & DaysOfOperation.Sunday,
136-
AnnotationSymbols =
137-
trip.StartTime > new TimeOnly(23, 30) || trip.StartTime < new TimeOnly(2, 0) ? [] : ["A"],
156+
DaysOfOperation = trip.DaysOfOperation & ~(DaysOfOperation.Friday | DaysOfOperation.Saturday),
157+
Connections =
158+
trip.StartTime > new TimeOnly(23, 30) || trip.StartTime < new TimeOnly(2, 0)
159+
? []
160+
: [ContinuesAs99(M2)],
138161
},
139162
trip with
140163
{
141164
RouteIndex = Original.Line.Routes.Length /* Kirschallee -> Pl.d.Einh./W. */,
142165
TimeProfileIndex = 0,
143-
DaysOfOperation = trip.DaysOfOperation & ~DaysOfOperation.Sunday,
144-
AnnotationSymbols =
145-
trip.StartTime == new TimeOnly(0, 51) || trip.StartTime == new TimeOnly(1, 11) ? [] : ["A"],
166+
DaysOfOperation = trip.DaysOfOperation & (DaysOfOperation.Friday | DaysOfOperation.Saturday),
167+
Connections =
168+
trip.StartTime == new TimeOnly(0, 51) || trip.StartTime == new TimeOnly(1, 11)
169+
? []
170+
: [ContinuesAs99(M2)],
146171
},
147172
];
148173
}

VipTimetable/Lines/Tram93/Tram93From20250110Until20250112.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,13 @@ trip with
183183
TimeProfileIndex = 0,
184184
DaysOfOperation = trip.DaysOfOperation & DaysOfOperation.Weekend,
185185
StartTime = trip.StartTime.AddMinutes(14),
186+
Connections = [new Line.TripCreate.Connection
187+
{
188+
Delay = M4,
189+
Type = Line.Trip.ConnectionType.ComesAs,
190+
ConnectingLineIdentifier = "tram92",
191+
ConnectingRouteIndex = 11,
192+
}]
186193
},
187194
];
188195
}

VipTimetable/Lines/Tram99/Tram99From20250110Until20250112.cs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,32 @@ trip with
197197
}
198198

199199
return returnTrips ?? [trip];
200-
}).Where(trip => trip.DaysOfOperation != DaysOfOperation.None),
200+
}).Where(trip => trip.DaysOfOperation != DaysOfOperation.None).Select(trip =>
201+
{
202+
if (trip.RouteIndex.Equals(7) && trip.StartTime.IsBetween(new TimeOnly(20, 0), new TimeOnly(2, 0)))
203+
{
204+
return trip with
205+
{
206+
Connections =
207+
[
208+
new Line.TripCreate.Connection
209+
{
210+
Delay = trip.StartTime switch
211+
{
212+
_ when trip.StartTime == new TimeOnly(20, 5) => M0,
213+
_ when trip.StartTime == new TimeOnly(20, 25) => M5,
214+
_ => M2,
215+
},
216+
Type = Line.Trip.ConnectionType.ComesAs,
217+
ConnectingLineIdentifier = "tram92",
218+
ConnectingRouteIndex = 11,
219+
}
220+
],
221+
};
222+
}
223+
224+
return trip;
225+
}),
201226
..new Line.TripCreate
202227
{
203228
RouteIndex = Original.Line.Routes.Length,

0 commit comments

Comments
 (0)