Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/main/java/org/mtransit/parser/DefaultAgencyTools.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.mtransit.parser;

import static org.mtransit.parser.Constants.EMPTY;
import static org.mtransit.parser.gtfs.data.GSpecExtKt.fixMissingTripDirectionIds;

import androidx.annotation.Discouraged;
import androidx.annotation.VisibleForTesting;
Expand Down Expand Up @@ -186,6 +187,7 @@ public void start(@NotNull String[] args) {
final long start = System.currentTimeMillis();
final GSpec gtfs = GReader.readGtfsZipFile(args[0], this, false, false);
MDataChangedManager.avoidCalendarDatesDataChanged(lastServiceDates, gtfs, this);
fixMissingTripDirectionIds(gtfs);
gtfs.cleanupStops();
gtfs.cleanupExcludedData();
gtfs.cleanupStopTimesPickupDropOffTypes(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ data class RouteConfig(
val tripIdNotUniqueAllowed: Boolean = false, // OPT-IN feature
@SerialName("trip_id_clean_merged")
val tripIdCleanMerged: Boolean = false, // OPT-IN feature
@SerialName("direction_id_use_other_trips_with_same_headsign")
val directionIdUseOtherTripsWithSameHeadsign: Boolean = false, // OPT-IN feature
// DIRECTION
@SerialName("direction_types")
val directionTypes: List<Int> = emptyList(),
Expand Down
45 changes: 15 additions & 30 deletions src/main/java/org/mtransit/parser/gtfs/data/GSpec.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ public class GSpec {
private static final boolean LOG_REMOVED = false;
// private static final boolean LOG_REMOVED = true; // DEBUG

private static final boolean USE_DB_ONLY = false;
// private static final boolean USE_DB_ONLY = true; // WIP
protected static final boolean USE_DB_ONLY = false;
// protected static final boolean USE_DB_ONLY = true; // WIP

@NotNull
private final Map<Integer, GAgency> agenciesCache = new HashMap<>();
Expand Down Expand Up @@ -355,7 +355,7 @@ public void addTrip(@NotNull GTrip gTrip, @Nullable PreparedStatement insertStop
}

@NotNull
private Collection<Integer> getAllTripRouteIdInts() {
protected Collection<Integer> getAllTripRouteIdInts() {
if (USE_DB_ONLY) {
Comment thread
mmathieum marked this conversation as resolved.
return GIDs.getInts(GTFSDataBase.selectTripRouteIds());
}
Expand All @@ -369,25 +369,6 @@ public int readTripsCount() {
return CollectionUtils.totalMapSize(this.routeIdIntTripsCache);
}

public void updateTripDirectionId(@NotNull GDirectionId gDirectionId, @Nullable Collection<Integer> tripIdInts) {
updateTripDirectionId(gDirectionId.getId(), tripIdInts);
}

@SuppressWarnings("WeakerAccess")
public void updateTripDirectionId(int directionId, @Nullable Collection<Integer> tripIdInts) {
if (tripIdInts == null) {
return;
}
List<Integer> routeIdInts = new ArrayList<>();
for (Integer tripIdInt : tripIdInts) {
routeIdInts.add(getTripRouteId(tripIdInt));
}
for (Integer routeIdInt : routeIdInts) {
GTrip.updateDirectionIdForTrips(getRouteTrips(routeIdInt), tripIdInts, directionId);
GTFSDataBase.updateTrip(GIDs.getStrings(tripIdInts), directionId);
}
}

@Nullable
public GTrip getTrip(int tripIdInt) {
if (USE_DB_ONLY) {
Expand All @@ -406,7 +387,7 @@ public GTrip getTrip(int tripIdInt) {
}

@Nullable
private Integer getTripRouteId(Integer tripIdInt) {
protected Integer getTripRouteId(int tripIdInt) {
return this.tripIdIntRouteIdInt.get(tripIdInt);
}

Expand Down Expand Up @@ -471,10 +452,12 @@ public List<GStopTime> getStopTimes(long mRouteId, int gTripIdInt) {
}

@NotNull
public List<GStopTime> getStopTimes(long mRouteId,
int gTripIdInt,
@SuppressWarnings("unused") @Nullable String optGStopId,
@SuppressWarnings("unused") @Nullable Integer optGStopSequence) {
public List<GStopTime> getStopTimes(
long mRouteId,
int gTripIdInt,
@SuppressWarnings("unused") @Nullable String optGStopId,
@SuppressWarnings("unused") @Nullable Integer optGStopSequence
) {
GenerateMObjectsTask routeGenerator = this.routeGenerators.get(mRouteId);
if (routeGenerator != null) {
return routeGenerator.getTripGStopTimes(gTripIdInt);
Expand Down Expand Up @@ -796,9 +779,11 @@ public void generateStopTimesFromFrequencies(@SuppressWarnings("unused") @NotNul
MTLog.log("- Stop times: %d (after) (new: %d)", readStopTimesCount(), st);
}

private void setDepartureTimeCal(@NotNull Calendar calendar,
@NotNull GStopTime gStopTime,
@NotNull List<GStopTime> tripStopTimes) {
private void setDepartureTimeCal(
@NotNull Calendar calendar,
@NotNull GStopTime gStopTime,
@NotNull List<GStopTime> tripStopTimes
) {
if (gStopTime.hasDepartureTime()) {
calendar.setTimeInMillis(gStopTime.getDepartureTimeMs());
} else {
Expand Down
45 changes: 45 additions & 0 deletions src/main/java/org/mtransit/parser/gtfs/data/GSpecExt.kt
Original file line number Diff line number Diff line change
@@ -1,3 +1,48 @@
package org.mtransit.parser.gtfs.data

import org.mtransit.parser.MTLog
import org.mtransit.parser.config.Configs
import org.mtransit.parser.db.GTFSDataBase
import org.mtransit.parser.gtfs.data.GSpec.USE_DB_ONLY
import org.mtransit.parser.gtfs.data.GTrip.Companion.updateDirectionId

fun GSpec.getRoute(gTrip: GTrip) = this.getRoute(gTrip.routeIdInt)

fun GSpec.updateTripDirectionId(directionId: Int, tripIdInts: Collection<Int>?) {
tripIdInts ?: return
if (!USE_DB_ONLY) {
tripIdInts
.mapNotNull { getTripRouteId(it) }
.distinct()
.forEach { routeIdInt ->
getRouteTrips(routeIdInt).updateDirectionId(tripIdInts, directionId)
}
}
GTFSDataBase.updateTrip(tripIds = GIDs.getStrings(tripIdInts), directionId)
}

fun GSpec.fixMissingTripDirectionIds() {
if (!Configs.routeConfig.directionIdUseOtherTripsWithSameHeadsign) return
MTLog.log("Try fixing GTFS trips w/o direction IDs...")
Comment thread
mmathieum marked this conversation as resolved.
var tripIdDirectionFixed = 0
getAllTripRouteIdInts().forEach { routeIdInt ->
val gRouteTrips = getRouteTrips(routeIdInt)
gRouteTrips
.filter { it.directionIdOrOriginal == null }
.groupBy { it.tripHeadsign }
.forEach { (tripHeadsign, gTripsNoDirectionId) ->
if (tripHeadsign == null) return@forEach
val distinctOriginalDirectionIds = gRouteTrips
.asSequence()
.filter { it.tripHeadsign == tripHeadsign }
.mapNotNull { it.directionIdOrOriginal }
.distinct()
.toList()
distinctOriginalDirectionIds.singleOrNull()?.let { originalDirectionId ->
updateTripDirectionId(originalDirectionId, gTripsNoDirectionId.map { it.tripIdInt })
tripIdDirectionFixed += gTripsNoDirectionId.size
}
}
}
MTLog.log("Try fixing GTFS trips w/o direction IDs... DONE (%d fixed trips with direction ID)", tripIdDirectionFixed)
}
37 changes: 12 additions & 25 deletions src/main/java/org/mtransit/parser/gtfs/data/GTrip.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,14 @@ data class GTrip(
bikesAllowed = bikesAllowed,
)

val directionId: Int?
get() = directionIdE.originalId() // optional
@set:Discouraged(message = "Should not be changed")
var directionId: Int?
get() {
return directionIdE.originalId() // optional
}
private set(value) {
this.directionIdE = GDirectionId.parse(value)
}

@Suppress("unused")
val directionIdOrDefault: Int
Expand All @@ -57,12 +63,6 @@ data class GTrip(
val directionIdOrOriginal: Int?
get() = directionIdE.originalId()

@Suppress("unused")
@Discouraged(message = "Should not be changed")
fun setDirectionId(newDirectionId: Int?) {
this.directionIdE = GDirectionId.parse(newDirectionId)
}

fun hasTripHeadsign() = !this.tripHeadsign.isNullOrBlank()

@Suppress("unused")
Expand Down Expand Up @@ -214,23 +214,10 @@ data class GTrip(
}

@JvmStatic
fun updateDirectionIdForTrips(gTrips: MutableList<GTrip>, tripIdInts: Collection<Int>, directionId: Int): List<GTrip> {
return updateList(
gTrips = gTrips,
condition = { tripIdInts.contains(it.tripIdInt) },
updateTrip = { it.copy(directionIdE = GDirectionId.parse(directionId)) }
)
}

fun updateList(gTrips: MutableList<GTrip>, condition: (GTrip) -> Boolean, updateTrip: (GTrip) -> GTrip): List<GTrip> {
for (i in 0 until gTrips.size) {
val gTrip = gTrips[i]
if (condition(gTrip)) {
gTrips[i] = updateTrip(gTrip)
}
fun MutableList<GTrip>.updateDirectionId(tripIdInts: Collection<Int>, directionId: Int) =
replaceAll { gTrip ->
if (!tripIdInts.contains(gTrip.tripIdInt)) return@replaceAll gTrip
gTrip.copy(directionIdE = GDirectionId.parse(directionId))
}

return gTrips
}
}
}
18 changes: 9 additions & 9 deletions src/main/java/org/mtransit/parser/mt/MDirectionHeadSignFinder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ object MDirectionHeadSignFinder {
val gRoute = directionRouteIdInts[directionId].takeIf { it?.size == 1 }?.getOrNull(0)?.let { routeGTFS.getRoute(it) }
lastStopDirectionHeadSigns[directionId] =
agencyTools.cleanDirectionHeadsign(gRoute, directionId, true, false, false, agencyTools.cleanStopName(stop.stopName))
MTLog.logDebug("$routeId: $directionId Stop '${stop.toStringPlus(false)}' > '${lastStopDirectionHeadSigns[directionId]}'.")
MTLog.logDebug("$routeId: $directionId: - last stop '${stop.toStringPlus(false)}' > '${lastStopDirectionHeadSigns[directionId]}'.")
}
val allDirectionHeadSignsEmpty: Boolean = directionHeadSigns
.map { (_, headSign) -> headSign }
Expand Down Expand Up @@ -743,7 +743,7 @@ object MDirectionHeadSignFinder {
MTLog.log(
!dataLossAuthorized,
"$routeId: $directionId: #2 goes for WAY more stops ($stopIdIntsAfterCommonCount2) than " +
"#1 ($stopIdIntsAfterCommonCount1:$stopTimesHeadSign1) " +
"#1 ($stopIdIntsAfterCommonCount1:'$stopTimesHeadSign1') " +
"-> '$stopTimesHeadSign2'"
)
return MergedTrip(
Expand All @@ -762,7 +762,7 @@ object MDirectionHeadSignFinder {
MTLog.log(
!dataLossAuthorized,
"$routeId: $directionId: #1 goes for WAY more stops ($stopIdIntsAfterCommonCount1) than " +
"#2 ($stopIdIntsAfterCommonCount2:$stopTimesHeadSign2) " +
"#2 ($stopIdIntsAfterCommonCount2:'$stopTimesHeadSign2') " +
"-> '$stopTimesHeadSign1'"
)
return MergedTrip(
Expand Down Expand Up @@ -970,7 +970,7 @@ object MDirectionHeadSignFinder {
!dataLossAuthorized,
"$routeId: $directionId: distance from last common to " +
"#1 last ($distanceToStop1) > " +
"#2 last ($distanceToStop2) ($stopTimesHeadSign2) " +
"#2 last ($distanceToStop2) ('$stopTimesHeadSign2') " +
"-> '$stopTimesHeadSign1'"
)
return MergedTrip(
Expand All @@ -987,7 +987,7 @@ object MDirectionHeadSignFinder {
!dataLossAuthorized,
"$routeId: $directionId: distance from last common to " +
"#2 last ($distanceToStop2) > " +
"#1 last ($distanceToStop1) ($stopTimesHeadSign1) " +
"#1 last ($distanceToStop1) ('$stopTimesHeadSign1') " +
"-> '$stopTimesHeadSign2'"
)
return MergedTrip(
Expand All @@ -1006,18 +1006,18 @@ object MDirectionHeadSignFinder {
if (dataLossAuthorized) {
throw MTLog.Fatal(
"$routeId: $directionId: Unresolved situation! \n" +
"- #1: $stopTimesHeadSign1. \n" +
"- #1: '$stopTimesHeadSign1'. \n" +
" Stops: ${stopTimesList1.map { gStopTime -> "\n - ${gStopTime.toStringPlus(false)}" }} \n" +
"- #2: $stopTimesHeadSign2. \n" +
"- #2: '$stopTimesHeadSign2'. \n" +
" Stops: ${stopTimesList2.map { gStopTime -> "\n - ${gStopTime.toStringPlus(false)}" }} \n" +
"!"
)
}
logMerge(
!dataLossAuthorized, "$routeId: $directionId: unresolved situation > no head-sign (" +
"$stopTimesHeadSign1:${GIDs.toStringPlus(stopTimesList1.firstOrNull()?.tripIdInt)}" +
"'$stopTimesHeadSign1':${GIDs.toStringPlus(stopTimesList1.firstOrNull()?.tripIdInt)}" +
"|" +
"$stopTimesHeadSign2:${GIDs.toStringPlus(stopTimesList2.firstOrNull()?.tripIdInt)}" +
"'$stopTimesHeadSign2':${GIDs.toStringPlus(stopTimesList2.firstOrNull()?.tripIdInt)}" +
")."
)
return null
Expand Down
11 changes: 6 additions & 5 deletions src/main/java/org/mtransit/parser/mt/MDirectionSplitter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.mtransit.parser.gtfs.data.GIDs
import org.mtransit.parser.gtfs.data.GRoute
import org.mtransit.parser.gtfs.data.GSpec
import org.mtransit.parser.gtfs.data.GTrip
import org.mtransit.parser.gtfs.data.updateTripDirectionId
import kotlin.math.min

object MDirectionSplitter {
Expand Down Expand Up @@ -60,8 +61,8 @@ object MDirectionSplitter {
}
if ((min(trips0Size, trips1Size).toFloat() / gRouteTrips.size) > .33f) {
// TODO check if directions candidates group match existing split to keep original direction IDs
routeGTFS.updateTripDirectionId(GDirectionId.NEW_1, headSignToGTripIdInts[sortedHeadSigns[0]])
routeGTFS.updateTripDirectionId(GDirectionId.NEW_2, headSignToGTripIdInts[sortedHeadSigns[1]])
routeGTFS.updateTripDirectionId(GDirectionId.NEW_1.id, headSignToGTripIdInts[sortedHeadSigns[0]])
routeGTFS.updateTripDirectionId(GDirectionId.NEW_2.id, headSignToGTripIdInts[sortedHeadSigns[1]])
MTLog.log("$routeId: Splitting directions... DONE (with trip head-signs)")
return
}
Expand All @@ -84,7 +85,7 @@ object MDirectionSplitter {
) {
MTLog.log("$routeId: Keep original direction ID")
} else {
routeGTFS.updateTripDirectionId(GDirectionId.NEW_1, directionsCandidates[0].tripIdInts)
routeGTFS.updateTripDirectionId(GDirectionId.NEW_1.id, directionsCandidates[0].tripIdInts)
}
}

Expand All @@ -95,8 +96,8 @@ object MDirectionSplitter {
} else {
GDirectionId.NEW_1 to GDirectionId.NEW_2
}
routeGTFS.updateTripDirectionId(direction0, directionsCandidates[0].tripIdInts)
routeGTFS.updateTripDirectionId(direction1, directionsCandidates[1].tripIdInts)
routeGTFS.updateTripDirectionId(direction0.id, directionsCandidates[0].tripIdInts)
routeGTFS.updateTripDirectionId(direction1.id, directionsCandidates[1].tripIdInts)
}

else -> {
Expand Down