Search in sources :

Example 6 with Stop

use of org.opentripplanner.model.Stop in project OpenTripPlanner by opentripplanner.

the class TimetableHelper method createUpdatedTripTimes.

/**
 * Apply the TripUpdate to the appropriate TripTimes from this Timetable. The existing TripTimes
 * must not be modified directly because they may be shared with the underlying
 * scheduledTimetable, or other updated Timetables. The {@link TimetableSnapshot} performs the
 * protective copying of this Timetable. It is not done in this update method to avoid
 * repeatedly cloning the same Timetable when several updates are applied to it at once. We
 * assume here that all trips in a timetable are from the same feed, which should always be the
 * case.
 *
 * @param journey  SIRI-ET EstimatedVehicleJourney
 * @param timeZone time zone of trip update
 * @param tripId
 * @return new copy of updated TripTimes after TripUpdate has been applied on TripTimes of trip
 * with the id specified in the trip descriptor of the TripUpdate; null if something
 * went wrong
 */
public static TripTimes createUpdatedTripTimes(final Graph graph, Timetable timetable, EstimatedVehicleJourney journey, TimeZone timeZone, FeedScopedId tripId) {
    if (journey == null) {
        return null;
    }
    int tripIndex = timetable.getTripIndex(tripId);
    if (tripIndex == -1) {
        LOG.debug("tripId {} not found in pattern.", tripId);
        return null;
    }
    final TripTimes existingTripTimes = timetable.getTripTimes(tripIndex);
    TripTimes oldTimes = new TripTimes(existingTripTimes);
    if (journey.isCancellation() != null && journey.isCancellation()) {
        oldTimes.cancel();
        return oldTimes;
    }
    EstimatedVehicleJourney.EstimatedCalls journeyEstimatedCalls = journey.getEstimatedCalls();
    EstimatedVehicleJourney.RecordedCalls journeyRecordedCalls = journey.getRecordedCalls();
    if (journeyEstimatedCalls == null) {
        return null;
    }
    List<EstimatedCall> estimatedCalls = journeyEstimatedCalls.getEstimatedCalls();
    List<RecordedCall> recordedCalls;
    if (journeyRecordedCalls != null) {
        recordedCalls = journeyRecordedCalls.getRecordedCalls();
    } else {
        recordedCalls = new ArrayList<>();
    }
    boolean stopPatternChanged = false;
    Stop[] modifiedStops = timetable.pattern.stopPattern.stops;
    Trip trip = getTrip(tripId, timetable);
    List<StopTime> modifiedStopTimes = createModifiedStopTimes(timetable, oldTimes, journey, trip, new RoutingService(graph));
    if (modifiedStopTimes == null) {
        return null;
    }
    TripTimes newTimes = new TripTimes(trip, modifiedStopTimes, graph.deduplicator);
    // Populate missing data from existing TripTimes
    newTimes.serviceCode = oldTimes.serviceCode;
    int callCounter = 0;
    ZonedDateTime departureDate = null;
    Set<Object> alreadyVisited = new HashSet<>();
    boolean isJourneyPredictionInaccurate = (journey.isPredictionInaccurate() != null && journey.isPredictionInaccurate());
    int departureFromPreviousStop = 0;
    int lastArrivalDelay = 0;
    int lastDepartureDelay = 0;
    for (Stop stop : modifiedStops) {
        boolean foundMatch = false;
        for (RecordedCall recordedCall : recordedCalls) {
            if (alreadyVisited.contains(recordedCall)) {
                continue;
            }
            // Current stop is being updated
            foundMatch = stop.getId().getId().equals(recordedCall.getStopPointRef().getValue());
            if (!foundMatch && stop.isPartOfStation()) {
                Stop alternativeStop = graph.index.getStopForId(new FeedScopedId(stop.getId().getFeedId(), recordedCall.getStopPointRef().getValue()));
                if (alternativeStop != null && stop.isPartOfSameStationAs(alternativeStop)) {
                    foundMatch = true;
                    stopPatternChanged = true;
                }
            }
            if (foundMatch) {
                if (departureDate == null) {
                    departureDate = recordedCall.getAimedDepartureTime();
                    if (departureDate == null) {
                        departureDate = recordedCall.getAimedArrivalTime();
                    }
                    if (oldTimes.getDepartureTime(0) > 86400) {
                        // The "departure-date" for this trip is set to "yesterday" (or before) even though it actually departs "today"
                        // calculate number of offset-days
                        int dayOffsetCount = oldTimes.getDepartureTime(0) / 86400;
                        departureDate = departureDate.minusDays(dayOffsetCount);
                    }
                }
                // Flag as recorded
                newTimes.setRecorded(callCounter, true);
                if (recordedCall.isCancellation() != null) {
                    newTimes.setCancelledStop(callCounter, recordedCall.isCancellation());
                }
                newTimes.setDropoffType(callCounter, timetable.pattern.stopPattern.dropoffs[callCounter]);
                newTimes.setPickupType(callCounter, timetable.pattern.stopPattern.pickups[callCounter]);
                int arrivalTime = newTimes.getArrivalTime(callCounter);
                int realtimeArrivalTime = arrivalTime;
                if (recordedCall.getActualArrivalTime() != null) {
                    realtimeArrivalTime = calculateSecondsSinceMidnight(departureDate, recordedCall.getActualArrivalTime());
                } else if (recordedCall.getExpectedArrivalTime() != null) {
                    realtimeArrivalTime = calculateSecondsSinceMidnight(departureDate, recordedCall.getExpectedArrivalTime());
                } else if (recordedCall.getAimedArrivalTime() != null) {
                    realtimeArrivalTime = calculateSecondsSinceMidnight(departureDate, recordedCall.getAimedArrivalTime());
                }
                int arrivalDelay = realtimeArrivalTime - arrivalTime;
                newTimes.updateArrivalDelay(callCounter, arrivalDelay);
                lastArrivalDelay = arrivalDelay;
                int departureTime = newTimes.getDepartureTime(callCounter);
                int realtimeDepartureTime = departureTime;
                if (recordedCall.getActualDepartureTime() != null) {
                    realtimeDepartureTime = calculateSecondsSinceMidnight(departureDate, recordedCall.getActualDepartureTime());
                } else if (recordedCall.getExpectedDepartureTime() != null) {
                    realtimeDepartureTime = calculateSecondsSinceMidnight(departureDate, recordedCall.getExpectedDepartureTime());
                } else if (recordedCall.getAimedDepartureTime() != null) {
                    realtimeDepartureTime = calculateSecondsSinceMidnight(departureDate, recordedCall.getAimedDepartureTime());
                }
                if (realtimeDepartureTime < realtimeArrivalTime) {
                    realtimeDepartureTime = realtimeArrivalTime;
                }
                int departureDelay = realtimeDepartureTime - departureTime;
                newTimes.updateDepartureDelay(callCounter, departureDelay);
                lastDepartureDelay = departureDelay;
                departureFromPreviousStop = newTimes.getDepartureTime(callCounter);
                alreadyVisited.add(recordedCall);
                break;
            }
        }
        if (!foundMatch) {
            for (EstimatedCall estimatedCall : estimatedCalls) {
                if (alreadyVisited.contains(estimatedCall)) {
                    continue;
                }
                // Current stop is being updated
                foundMatch = stop.getId().getId().equals(estimatedCall.getStopPointRef().getValue());
                if (!foundMatch && stop.isPartOfStation()) {
                    Stop alternativeStop = graph.index.getStopForId(new FeedScopedId(stop.getId().getFeedId(), estimatedCall.getStopPointRef().getValue()));
                    if (alternativeStop != null && stop.isPartOfSameStationAs(alternativeStop)) {
                        foundMatch = true;
                        stopPatternChanged = true;
                    }
                }
                if (foundMatch) {
                    if (departureDate == null) {
                        departureDate = estimatedCall.getAimedDepartureTime();
                        if (departureDate == null) {
                            departureDate = estimatedCall.getAimedArrivalTime();
                        }
                    }
                    if (estimatedCall.isCancellation() != null) {
                        newTimes.setCancelledStop(callCounter, estimatedCall.isCancellation());
                    }
                    boolean isCallPredictionInaccurate = estimatedCall.isPredictionInaccurate() != null && estimatedCall.isPredictionInaccurate();
                    // Set flag for inaccurate prediction if either call OR journey has inaccurate-flag set.
                    newTimes.setPredictionInaccurate(callCounter, (isJourneyPredictionInaccurate | isCallPredictionInaccurate));
                    // Update dropoff-/pickuptype only if status is cancelled
                    CallStatusEnumeration arrivalStatus = estimatedCall.getArrivalStatus();
                    if (arrivalStatus == CallStatusEnumeration.CANCELLED) {
                        newTimes.setDropoffType(callCounter, PICKDROP_NONE);
                    }
                    CallStatusEnumeration departureStatus = estimatedCall.getDepartureStatus();
                    if (departureStatus == CallStatusEnumeration.CANCELLED) {
                        newTimes.setPickupType(callCounter, PICKDROP_NONE);
                    }
                    int arrivalTime = newTimes.getArrivalTime(callCounter);
                    int realtimeArrivalTime = -1;
                    if (estimatedCall.getExpectedArrivalTime() != null) {
                        realtimeArrivalTime = calculateSecondsSinceMidnight(departureDate, estimatedCall.getExpectedArrivalTime());
                    } else if (estimatedCall.getAimedArrivalTime() != null) {
                        realtimeArrivalTime = calculateSecondsSinceMidnight(departureDate, estimatedCall.getAimedArrivalTime());
                    }
                    int departureTime = newTimes.getDepartureTime(callCounter);
                    int realtimeDepartureTime = departureTime;
                    if (estimatedCall.getExpectedDepartureTime() != null) {
                        realtimeDepartureTime = calculateSecondsSinceMidnight(departureDate, estimatedCall.getExpectedDepartureTime());
                    } else if (estimatedCall.getAimedDepartureTime() != null) {
                        realtimeDepartureTime = calculateSecondsSinceMidnight(departureDate, estimatedCall.getAimedDepartureTime());
                    }
                    if (realtimeArrivalTime == -1) {
                        realtimeArrivalTime = realtimeDepartureTime;
                    }
                    if (realtimeDepartureTime < realtimeArrivalTime) {
                        realtimeDepartureTime = realtimeArrivalTime;
                    }
                    int arrivalDelay = realtimeArrivalTime - arrivalTime;
                    newTimes.updateArrivalDelay(callCounter, arrivalDelay);
                    lastArrivalDelay = arrivalDelay;
                    int departureDelay = realtimeDepartureTime - departureTime;
                    newTimes.updateDepartureDelay(callCounter, departureDelay);
                    lastDepartureDelay = departureDelay;
                    departureFromPreviousStop = newTimes.getDepartureTime(callCounter);
                    alreadyVisited.add(estimatedCall);
                    break;
                }
            }
        }
        if (!foundMatch) {
            if (timetable.pattern.stopPattern.pickups[callCounter] == PICKDROP_NONE && timetable.pattern.stopPattern.dropoffs[callCounter] == PICKDROP_NONE) {
                // When newTimes contains stops without pickup/dropoff - set both arrival/departure to previous stop's departure
                // This necessary to accommodate the case when delay is reduced/eliminated between to stops with pickup/dropoff, and
                // multiple non-pickup/dropoff stops are in between.
                newTimes.updateArrivalTime(callCounter, departureFromPreviousStop);
                newTimes.updateDepartureTime(callCounter, departureFromPreviousStop);
            } else {
                int arrivalDelay = lastArrivalDelay;
                int departureDelay = lastDepartureDelay;
                if (lastArrivalDelay == 0 && lastDepartureDelay == 0) {
                    // No match has been found yet (i.e. still in RecordedCalls) - keep existing delays
                    arrivalDelay = existingTripTimes.getArrivalDelay(callCounter);
                    departureDelay = existingTripTimes.getDepartureDelay(callCounter);
                }
                newTimes.updateArrivalDelay(callCounter, arrivalDelay);
                newTimes.updateDepartureDelay(callCounter, departureDelay);
            }
            departureFromPreviousStop = newTimes.getDepartureTime(callCounter);
        }
        callCounter++;
    }
    if (stopPatternChanged) {
        // This update modified stopPattern
        newTimes.setRealTimeState(RealTimeState.MODIFIED);
    } else {
        // This is the first update, and StopPattern has not been changed
        newTimes.setRealTimeState(RealTimeState.UPDATED);
    }
    if (journey.isCancellation() != null && journey.isCancellation()) {
        LOG.debug("Trip is cancelled");
        newTimes.cancel();
    }
    if (!newTimes.timesIncreasing()) {
        LOG.info("TripTimes are non-increasing after applying SIRI delay propagation - LineRef {}, TripId {}.", journey.getLineRef().getValue(), tripId);
        return null;
    }
    if (newTimes.getNumStops() != timetable.pattern.stopPattern.stops.length) {
        return null;
    }
    LOG.debug("A valid TripUpdate object was applied using the Timetable class update method.");
    return newTimes;
}
Also used : Trip(org.opentripplanner.model.Trip) EstimatedVehicleJourney(uk.org.siri.siri20.EstimatedVehicleJourney) Stop(org.opentripplanner.model.Stop) RoutingService(org.opentripplanner.routing.RoutingService) RecordedCall(uk.org.siri.siri20.RecordedCall) ZonedDateTime(java.time.ZonedDateTime) TripTimes(org.opentripplanner.routing.trippattern.TripTimes) FeedScopedId(org.opentripplanner.model.FeedScopedId) EstimatedCall(uk.org.siri.siri20.EstimatedCall) CallStatusEnumeration(uk.org.siri.siri20.CallStatusEnumeration) StopTime(org.opentripplanner.model.StopTime) HashSet(java.util.HashSet)

Example 7 with Stop

use of org.opentripplanner.model.Stop in project OpenTripPlanner by opentripplanner.

the class TimetableHelper method createUpdatedTripTimes.

/**
 * Apply the TripUpdate to the appropriate TripTimes from this Timetable. The existing TripTimes
 * must not be modified directly because they may be shared with the underlying
 * scheduledTimetable, or other updated Timetables. The {@link TimetableSnapshot} performs the
 * protective copying of this Timetable. It is not done in this update method to avoid
 * repeatedly cloning the same Timetable when several updates are applied to it at once. We
 * assume here that all trips in a timetable are from the same feed, which should always be the
 * case.
 *
 * @param activity SIRI-VM VehicleActivity
 * @param timeZone time zone of trip update
 * @param tripId
 * @return new copy of updated TripTimes after TripUpdate has been applied on TripTimes of trip
 * with the id specified in the trip descriptor of the TripUpdate; null if something
 * went wrong
 */
public static TripTimes createUpdatedTripTimes(Timetable timetable, Graph graph, VehicleActivityStructure activity, TimeZone timeZone, FeedScopedId tripId) {
    if (activity == null) {
        return null;
    }
    MonitoredVehicleJourneyStructure mvj = activity.getMonitoredVehicleJourney();
    int tripIndex = timetable.getTripIndex(tripId);
    if (tripIndex == -1) {
        LOG.trace("tripId {} not found in pattern.", tripId);
        return null;
    }
    final TripTimes existingTripTimes = timetable.getTripTimes(tripIndex);
    TripTimes newTimes = new TripTimes(existingTripTimes);
    MonitoredCallStructure update = mvj.getMonitoredCall();
    if (update == null) {
        return null;
    }
    final List<Stop> stops = timetable.pattern.getStops();
    VehicleActivityStructure.MonitoredVehicleJourney monitoredVehicleJourney = activity.getMonitoredVehicleJourney();
    Duration delay = null;
    if (monitoredVehicleJourney != null) {
        delay = monitoredVehicleJourney.getDelay();
        int updatedDelay = 0;
        if (delay != null) {
            updatedDelay = delay.getSign() * (delay.getHours() * 3600 + delay.getMinutes() * 60 + delay.getSeconds());
        }
        MonitoredCallStructure monitoredCall = monitoredVehicleJourney.getMonitoredCall();
        if (monitoredCall != null && monitoredCall.getStopPointRef() != null) {
            boolean matchFound = false;
            int arrivalDelay = 0;
            int departureDelay = 0;
            for (int index = 0; index < newTimes.getNumStops(); ++index) {
                if (!matchFound) {
                    // Delay is set on a single stop at a time. When match is found - propagate delay on all following stops
                    final Stop stop = stops.get(index);
                    matchFound = stop.getId().getId().equals(monitoredCall.getStopPointRef().getValue());
                    if (!matchFound && stop.isPartOfStation()) {
                        FeedScopedId alternativeId = new FeedScopedId(stop.getId().getFeedId(), monitoredCall.getStopPointRef().getValue());
                        Stop alternativeStop = graph.index.getStopForId(alternativeId);
                        if (alternativeStop != null && alternativeStop.isPartOfStation()) {
                            matchFound = stop.isPartOfSameStationAs(alternativeStop);
                        }
                    }
                    if (matchFound) {
                        arrivalDelay = departureDelay = updatedDelay;
                    } else {
                        /*
                             * If updated delay is less than previously set delay, the existing delay needs to be adjusted to avoid
                             * non-increasing times causing updates to be rejected. Will only affect historical data.
                             */
                        arrivalDelay = Math.min(existingTripTimes.getArrivalDelay(index), updatedDelay);
                        departureDelay = Math.min(existingTripTimes.getDepartureDelay(index), updatedDelay);
                    }
                }
                newTimes.updateArrivalDelay(index, arrivalDelay);
                newTimes.updateDepartureDelay(index, departureDelay);
            }
        }
    }
    if (!newTimes.timesIncreasing()) {
        LOG.info("TripTimes are non-increasing after applying SIRI delay propagation - delay: {}", delay);
        return null;
    }
    // If state is already MODIFIED - keep existing state
    if (newTimes.getRealTimeState() != RealTimeState.MODIFIED) {
        // Make sure that updated trip times have the correct real time state
        newTimes.setRealTimeState(RealTimeState.UPDATED);
    }
    return newTimes;
}
Also used : MonitoredVehicleJourneyStructure(uk.org.siri.siri20.MonitoredVehicleJourneyStructure) Stop(org.opentripplanner.model.Stop) TripTimes(org.opentripplanner.routing.trippattern.TripTimes) FeedScopedId(org.opentripplanner.model.FeedScopedId) Duration(javax.xml.datatype.Duration) VehicleActivityStructure(uk.org.siri.siri20.VehicleActivityStructure) MonitoredCallStructure(uk.org.siri.siri20.MonitoredCallStructure)

Example 8 with Stop

use of org.opentripplanner.model.Stop in project OpenTripPlanner by opentripplanner.

the class LegacyGraphQLPlaceInterfaceTypeResolver method getType.

@Override
public GraphQLObjectType getType(TypeResolutionEnvironment environment) {
    Object o = environment.getObject();
    GraphQLSchema schema = environment.getSchema();
    if (o instanceof BikePark)
        return schema.getObjectType("BikePark");
    if (o instanceof BikeRentalStation)
        return schema.getObjectType("BikeRentalStation");
    // if (o instanceof CarPark) return schema.getObjectType("CarPark");
    if (o instanceof PatternAtStop)
        return schema.getObjectType("DepartureRow");
    if (o instanceof Stop)
        return schema.getObjectType("Stop");
    return null;
}
Also used : PatternAtStop(org.opentripplanner.routing.graphfinder.PatternAtStop) Stop(org.opentripplanner.model.Stop) PatternAtStop(org.opentripplanner.routing.graphfinder.PatternAtStop) BikePark(org.opentripplanner.routing.bike_park.BikePark) GraphQLSchema(graphql.schema.GraphQLSchema) BikeRentalStation(org.opentripplanner.routing.bike_rental.BikeRentalStation)

Example 9 with Stop

use of org.opentripplanner.model.Stop in project OpenTripPlanner by opentripplanner.

the class LegacyGraphQLQueryTypeImpl method node.

@Override
public DataFetcher<Object> node() {
    return environment -> {
        var args = new LegacyGraphQLTypes.LegacyGraphQLQueryTypeNodeArgs(environment.getArguments());
        String type = args.getLegacyGraphQLId().getType();
        String id = args.getLegacyGraphQLId().getId();
        RoutingService routingService = environment.<LegacyGraphQLRequestContext>getContext().getRoutingService();
        BikeRentalStationService bikerentalStationService = routingService.getBikerentalStationService();
        switch(type) {
            case "Agency":
                return routingService.getAgencyForId(FeedScopedId.parseId(id));
            case "Alert":
                // TODO
                return null;
            case "BikePark":
                return bikerentalStationService == null ? null : bikerentalStationService.getBikeParks().stream().filter(bikePark -> bikePark.id.equals(id)).findAny().orElse(null);
            case "BikeRentalStation":
                return bikerentalStationService == null ? null : bikerentalStationService.getBikeRentalStations().stream().filter(bikeRentalStation -> bikeRentalStation.id.equals(id)).findAny().orElse(null);
            case "CarPark":
                // TODO
                return null;
            case "Cluster":
                // TODO
                return null;
            case "DepartureRow":
                return PatternAtStop.fromId(routingService, id);
            case "Pattern":
                return routingService.getTripPatternForId(FeedScopedId.parseId(id));
            case "placeAtDistance":
                {
                    String[] parts = id.split(";");
                    Relay.ResolvedGlobalId internalId = new Relay().fromGlobalId(parts[1]);
                    Object place = node().get(DataFetchingEnvironmentImpl.newDataFetchingEnvironment(environment).source(new Object()).arguments(Map.of("id", internalId)).build());
                    return new PlaceAtDistance(place, Double.parseDouble(parts[0]));
                }
            case "Route":
                return routingService.getRouteForId(FeedScopedId.parseId(id));
            case "Stop":
                return routingService.getStopForId(FeedScopedId.parseId(id));
            case "Stoptime":
                // TODO
                return null;
            case "stopAtDistance":
                {
                    String[] parts = id.split(";");
                    Stop stop = routingService.getStopForId(FeedScopedId.parseId(parts[1]));
                    // TODO: Add geometry
                    return new StopAtDistance(stop, Integer.parseInt(parts[0]), null, null, null);
                }
            case "TicketType":
                // TODO
                return null;
            case "Trip":
                return routingService.getTripForId().get(FeedScopedId.parseId(id));
            default:
                return null;
        }
    };
}
Also used : DataFetchingEnvironment(graphql.schema.DataFetchingEnvironment) Arrays(java.util.Arrays) RoutingService(org.opentripplanner.routing.RoutingService) Trip(org.opentripplanner.model.Trip) Date(java.util.Date) TransitStopVertex(org.opentripplanner.routing.vertextype.TransitStopVertex) Coordinate(org.locationtech.jts.geom.Coordinate) ServiceDate(org.opentripplanner.model.calendar.ServiceDate) LegacyGraphQLRequestContext(org.opentripplanner.ext.legacygraphqlapi.LegacyGraphQLRequestContext) PlaceType(org.opentripplanner.routing.graphfinder.PlaceType) PatternAtStop(org.opentripplanner.routing.graphfinder.PatternAtStop) TripTimeShort(org.opentripplanner.model.TripTimeShort) Duration(java.time.Duration) Map(java.util.Map) BicycleOptimizeType(org.opentripplanner.routing.core.BicycleOptimizeType) TransitMode(org.opentripplanner.model.TransitMode) FeedScopedId(org.opentripplanner.model.FeedScopedId) Station(org.opentripplanner.model.Station) BikePark(org.opentripplanner.routing.bike_park.BikePark) GenericLocation(org.opentripplanner.model.GenericLocation) TripPattern(org.opentripplanner.model.TripPattern) Stop(org.opentripplanner.model.Stop) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) TransitAlert(org.opentripplanner.routing.alertpatch.TransitAlert) List(java.util.List) Stream(java.util.stream.Stream) BikeRentalStation(org.opentripplanner.routing.bike_rental.BikeRentalStation) ResourceBundleSingleton(org.opentripplanner.util.ResourceBundleSingleton) Relay(graphql.relay.Relay) PlaceAtDistance(org.opentripplanner.routing.graphfinder.PlaceAtDistance) StopAtDistance(org.opentripplanner.routing.graphfinder.StopAtDistance) LegacyGraphQLTypes(org.opentripplanner.ext.legacygraphqlapi.generated.LegacyGraphQLTypes) RoutingValidationException(org.opentripplanner.routing.error.RoutingValidationException) ArrayList(java.util.ArrayList) Lists(com.google.common.collect.Lists) Connection(graphql.relay.Connection) QualifiedModeSet(org.opentripplanner.api.parameter.QualifiedModeSet) QualifiedMode(org.opentripplanner.api.parameter.QualifiedMode) DataFetcher(graphql.schema.DataFetcher) ParameterException(org.opentripplanner.api.common.ParameterException) StreamSupport(java.util.stream.StreamSupport) GtfsRealtimeFuzzyTripMatcher(org.opentripplanner.updater.GtfsRealtimeFuzzyTripMatcher) SimpleListConnection(graphql.relay.SimpleListConnection) RoutingResponse(org.opentripplanner.routing.api.response.RoutingResponse) Agency(org.opentripplanner.model.Agency) DataFetchingEnvironmentImpl(graphql.schema.DataFetchingEnvironmentImpl) Consumer(java.util.function.Consumer) Route(org.opentripplanner.model.Route) BikeRentalStationService(org.opentripplanner.routing.bike_rental.BikeRentalStationService) LegacyGraphQLDataFetchers(org.opentripplanner.ext.legacygraphqlapi.generated.LegacyGraphQLDataFetchers) RoutingRequest(org.opentripplanner.routing.api.request.RoutingRequest) Envelope(org.locationtech.jts.geom.Envelope) Collections(java.util.Collections) FeedInfo(org.opentripplanner.model.FeedInfo) FareRuleSet(org.opentripplanner.routing.core.FareRuleSet) LegacyGraphQLRequestContext(org.opentripplanner.ext.legacygraphqlapi.LegacyGraphQLRequestContext) Relay(graphql.relay.Relay) PatternAtStop(org.opentripplanner.routing.graphfinder.PatternAtStop) Stop(org.opentripplanner.model.Stop) PlaceAtDistance(org.opentripplanner.routing.graphfinder.PlaceAtDistance) RoutingService(org.opentripplanner.routing.RoutingService) BikeRentalStationService(org.opentripplanner.routing.bike_rental.BikeRentalStationService) LegacyGraphQLTypes(org.opentripplanner.ext.legacygraphqlapi.generated.LegacyGraphQLTypes) StopAtDistance(org.opentripplanner.routing.graphfinder.StopAtDistance)

Example 10 with Stop

use of org.opentripplanner.model.Stop in project OpenTripPlanner by opentripplanner.

the class DirectTransferAnalyzer method buildGraph.

@Override
public void buildGraph(Graph graph, HashMap<Class<?>, Object> extra, DataImportIssueStore issueStore) {
    /* Initialize graph index which is needed by the nearby stop finder. */
    graph.index = new GraphIndex(graph);
    LOG.info("Analyzing transfers (this can be time consuming)...");
    List<TransferInfo> directTransfersTooLong = new ArrayList<>();
    List<TransferInfo> directTransfersNotFound = new ArrayList<>();
    DirectGraphFinder nearbyStopFinderEuclidian = new DirectGraphFinder(graph);
    StreetGraphFinder nearbyStopFinderStreets = new StreetGraphFinder(graph);
    int stopsAnalyzed = 0;
    for (TransitStopVertex originStopVertex : Iterables.filter(graph.getVertices(), TransitStopVertex.class)) {
        if (++stopsAnalyzed % 1000 == 0) {
            LOG.info("{} stops analyzed", stopsAnalyzed);
        }
        /* Find nearby stops by euclidean distance */
        Coordinate c0 = originStopVertex.getCoordinate();
        Map<Stop, StopAtDistance> stopsEuclidean = nearbyStopFinderEuclidian.findClosestStops(c0.y, c0.x, radiusMeters).stream().filter(t -> t.stop instanceof Stop).collect(Collectors.toMap(t -> (Stop) t.stop, t -> t));
        /* Find nearby stops by street distance */
        Map<Stop, StopAtDistance> stopsStreets = nearbyStopFinderStreets.findClosestStops(c0.y, c0.x, radiusMeters * RADIUS_MULTIPLIER).stream().filter(t -> t.stop instanceof Stop).collect(Collectors.toMap(t -> (Stop) t.stop, t -> t));
        Stop originStop = originStopVertex.getStop();
        /* Get stops found by both street and euclidean search */
        List<Stop> stopsConnected = stopsEuclidean.keySet().stream().filter(t -> stopsStreets.keySet().contains(t) && t != originStop).collect(Collectors.toList());
        /* Get stops found by euclidean search but not street search */
        List<Stop> stopsUnconnected = stopsEuclidean.keySet().stream().filter(t -> !stopsStreets.keySet().contains(t) && t != originStop).collect(Collectors.toList());
        for (Stop destStop : stopsConnected) {
            StopAtDistance euclideanStop = stopsEuclidean.get(destStop);
            StopAtDistance streetStop = stopsStreets.get(destStop);
            TransferInfo transferInfo = new TransferInfo(originStop, destStop, euclideanStop.distance, streetStop.distance);
            /* Log transfer where the street distance is too long compared to the euclidean distance */
            if (transferInfo.ratio > MIN_RATIO_TO_LOG && transferInfo.streetDistance > MIN_STREET_DISTANCE_TO_LOG) {
                directTransfersTooLong.add(transferInfo);
            }
        }
        for (Stop destStop : stopsUnconnected) {
            StopAtDistance euclideanStop = stopsEuclidean.get(destStop);
            /* Log transfers that are found by euclidean search but not by street search */
            directTransfersNotFound.add(new TransferInfo(originStop, destStop, euclideanStop.distance, -1));
        }
    }
    /* Sort by street distance to euclidean distance ratio before adding to issues */
    directTransfersTooLong.sort(Comparator.comparingDouble(t -> t.ratio));
    Collections.reverse(directTransfersTooLong);
    for (TransferInfo transferInfo : directTransfersTooLong) {
        issueStore.add(new TransferRoutingDistanceTooLong(transferInfo.origin, transferInfo.destination, transferInfo.directDistance, transferInfo.streetDistance, transferInfo.ratio));
    }
    /* Sort by direct distance before adding to issues */
    directTransfersNotFound.sort(Comparator.comparingDouble(t -> t.directDistance));
    for (TransferInfo transferInfo : directTransfersNotFound) {
        issueStore.add(new TransferCouldNotBeRouted(transferInfo.origin, transferInfo.destination, transferInfo.directDistance));
    }
    LOG.info("Done analyzing transfers. {} transfers could not be routed and {} transfers had a too long routing" + " distance.", directTransfersNotFound.size(), directTransfersTooLong.size());
}
Also used : StopAtDistance(org.opentripplanner.routing.graphfinder.StopAtDistance) Iterables(com.google.common.collect.Iterables) Logger(org.slf4j.Logger) StreetGraphFinder(org.opentripplanner.routing.graphfinder.StreetGraphFinder) Stop(org.opentripplanner.model.Stop) TransitStopVertex(org.opentripplanner.routing.vertextype.TransitStopVertex) LoggerFactory(org.slf4j.LoggerFactory) Coordinate(org.locationtech.jts.geom.Coordinate) DirectGraphFinder(org.opentripplanner.routing.graphfinder.DirectGraphFinder) HashMap(java.util.HashMap) Collectors(java.util.stream.Collectors) ArrayList(java.util.ArrayList) GraphIndex(org.opentripplanner.routing.graph.GraphIndex) TransferCouldNotBeRouted(org.opentripplanner.ext.transferanalyzer.annotations.TransferCouldNotBeRouted) List(java.util.List) GraphBuilderModule(org.opentripplanner.graph_builder.services.GraphBuilderModule) TransferRoutingDistanceTooLong(org.opentripplanner.ext.transferanalyzer.annotations.TransferRoutingDistanceTooLong) Graph(org.opentripplanner.routing.graph.Graph) Map(java.util.Map) DataImportIssueStore(org.opentripplanner.graph_builder.DataImportIssueStore) Comparator(java.util.Comparator) Collections(java.util.Collections) TransferRoutingDistanceTooLong(org.opentripplanner.ext.transferanalyzer.annotations.TransferRoutingDistanceTooLong) Stop(org.opentripplanner.model.Stop) ArrayList(java.util.ArrayList) StreetGraphFinder(org.opentripplanner.routing.graphfinder.StreetGraphFinder) Coordinate(org.locationtech.jts.geom.Coordinate) DirectGraphFinder(org.opentripplanner.routing.graphfinder.DirectGraphFinder) TransitStopVertex(org.opentripplanner.routing.vertextype.TransitStopVertex) GraphIndex(org.opentripplanner.routing.graph.GraphIndex) TransferCouldNotBeRouted(org.opentripplanner.ext.transferanalyzer.annotations.TransferCouldNotBeRouted) StopAtDistance(org.opentripplanner.routing.graphfinder.StopAtDistance)

Aggregations

Stop (org.opentripplanner.model.Stop)73 FeedScopedId (org.opentripplanner.model.FeedScopedId)25 ArrayList (java.util.ArrayList)24 TripPattern (org.opentripplanner.model.TripPattern)24 Trip (org.opentripplanner.model.Trip)21 ServiceDate (org.opentripplanner.model.calendar.ServiceDate)13 RoutingService (org.opentripplanner.routing.RoutingService)13 TransitStopVertex (org.opentripplanner.routing.vertextype.TransitStopVertex)13 HashSet (java.util.HashSet)12 Station (org.opentripplanner.model.Station)12 TripTimes (org.opentripplanner.routing.trippattern.TripTimes)11 List (java.util.List)10 Test (org.junit.Test)8 Route (org.opentripplanner.model.Route)8 StopTime (org.opentripplanner.model.StopTime)8 Collectors (java.util.stream.Collectors)7 GET (javax.ws.rs.GET)7 Path (javax.ws.rs.Path)7 ApiStop (org.opentripplanner.api.model.ApiStop)7 TripTimeShort (org.opentripplanner.model.TripTimeShort)7