org.opentripplanner.ext.transmodelapi.model.plan.TripQuery Maven / Gradle / Ivy
package org.opentripplanner.ext.transmodelapi.model.plan;
import graphql.Scalars;
import graphql.schema.GraphQLArgument;
import graphql.schema.GraphQLEnumType;
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLNonNull;
import graphql.schema.GraphQLOutputType;
import org.opentripplanner.ext.transmodelapi.TransmodelGraphQLPlanner;
import org.opentripplanner.ext.transmodelapi.model.DefaultRouteRequestType;
import org.opentripplanner.ext.transmodelapi.model.EnumTypes;
import org.opentripplanner.ext.transmodelapi.model.TransportModeSlack;
import org.opentripplanner.ext.transmodelapi.model.framework.LocationInputType;
import org.opentripplanner.ext.transmodelapi.support.GqlUtil;
import org.opentripplanner.routing.api.request.preference.RoutingPreferences;
import org.opentripplanner.routing.core.BicycleOptimizeType;
public class TripQuery {
public static GraphQLFieldDefinition create(
DefaultRouteRequestType routing,
GraphQLOutputType tripType,
GqlUtil gqlUtil
) {
RoutingPreferences preferences = routing.request.preferences();
return GraphQLFieldDefinition
.newFieldDefinition()
.name("trip")
.description(
"Input type for executing a travel search for a trip between two locations. Returns " +
"trip patterns describing suggested alternatives for the trip."
)
.type(new GraphQLNonNull(tripType))
.withDirective(gqlUtil.timingData)
.argument(
GraphQLArgument
.newArgument()
.name("dateTime")
.description(
"Date and time for the earliest time the user is willing to start the journey " +
"(if arriveBy=false/not set) or the latest acceptable time of arriving " +
"(arriveBy=true). Defaults to now"
)
.type(gqlUtil.dateTimeScalar)
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("searchWindow")
.description(
"The length of the search-window in minutes. This parameter is optional." +
"\n\n" +
"The search-window is defined as the duration between the earliest-departure-time(EDT) and " +
"the latest-departure-time(LDT). OTP will search for all itineraries in this departure " +
"window. If `arriveBy=true` the `dateTime` parameter is the latest-arrival-time, so OTP " +
"will dynamically calculate the EDT. Using a short search-window is faster than using a " +
"longer one, but the search duration is not linear. Using a \"too\" short search-window will " +
"waste resources server side, while using a search-window that is too long will be slow." +
"\n\n" +
"OTP will dynamically calculate a reasonable value for the search-window, if not provided. The " +
"calculation comes with a significant overhead (10-20% extra). Whether you should use the " +
"dynamic calculated value or pass in a value depends on your use-case. For a travel planner " +
"in a small geographical area, with a dense network of public transportation, a fixed value " +
"between 40 minutes and 2 hours makes sense. To find the appropriate search-window, adjust it " +
"so that the number of itineraries on average is around the wanted `numItineraries`. Make " +
"sure you set the `numItineraries` to a high number while testing. For a country wide area like " +
"Norway, using the dynamic search-window is the best." +
"\n\n" +
"When paginating, the search-window is calculated using the `numItineraries` in the original " +
"search together with statistics from the search for the last page. This behaviour is " +
"configured server side, and can not be overridden from the client." +
"\n\n" +
"The search-window used is returned to the response metadata as `searchWindowUsed` for " +
"debugging purposes."
)
.type(Scalars.GraphQLInt)
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("pageCursor")
.description(
"Use the cursor to go to the next \"page\" of itineraries. Copy the cursor from " +
"the last response and keep the original request as is. This will enable you to " +
"search for itineraries in the next or previous time-window."
)
.type(Scalars.GraphQLString)
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("timetableView")
.description(
"Search for the best trip options within a time window. If `true` two " +
"TripPatterns are considered optimal if one is better on arrival time" +
"(earliest wins) and the other is better on departure time(latest wins)." +
"In combination with `arriveBy` this parameter cover the following 3 use " +
"cases:\n\n" +
"\n" +
" - Traveler want to find the best alternative within a time window. Set " +
" `timetableView=true` and `arriveBy=false`. This is the default, and if " +
" the intention of the traveler is unknown it gives the best result, " +
" because it includes the two next use-cases. This option also work well " +
" with paging. Setting the `arriveBy=true`, covers the same use-case, but " +
" the input time is interpreted as latest-arrival-time, and not " +
" earliest-departure-time.\n" +
"\n" +
" - Traveler want to find the best alternative with departure after a " +
" specific time. For example: I am at the station now and want to get " +
" home as quickly as possible. Set `timetableView=false` and " +
" `arriveBy=false`. Do not support paging.\n" +
"\n" +
" - Traveler want to find the best alternative with arrival before a" +
" specific time. For example going to a meeting. Set `timetableView=false` " +
" and `arriveBy=true`. Do not support paging.\n" +
"\n" +
"Default: `true`"
)
.type(Scalars.GraphQLBoolean)
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("from")
.description("The start location")
.type(new GraphQLNonNull(LocationInputType.INPUT_TYPE))
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("to")
.description("The end location")
.type(new GraphQLNonNull(LocationInputType.INPUT_TYPE))
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("arriveBy")
.description(
"Whether the trip should depart at dateTime (false, the default), or arrive at " +
"dateTime. See `timetableView` for use-cases where this parameter is relevant."
)
.type(Scalars.GraphQLBoolean)
.defaultValue(routing.request.arriveBy())
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("wheelchairAccessible")
.description(
"Whether the trip must be wheelchair accessible. Supported for the street part to " +
"the search, not implemented for the transit jet."
)
.type(Scalars.GraphQLBoolean)
.defaultValue(routing.request.wheelchair())
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("ignoreRealtimeUpdates")
.description("When true, realtime updates are ignored during this search.")
.type(Scalars.GraphQLBoolean)
.defaultValue(preferences.transit().ignoreRealtimeUpdates())
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("includePlannedCancellations")
.description(
"When true, service journeys cancelled in scheduled route data will be included during this search."
)
.type(Scalars.GraphQLBoolean)
.defaultValue(preferences.transit().includePlannedCancellations())
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("locale")
.description(
"The preferable language to use for text targeted the end user. Note! The data " +
"quality is limited, only stop and quay names are translates, and not in all " +
"places of the API."
)
.type(EnumTypes.LOCALE)
.defaultValue("no")
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("modes")
.description(
"The set of access/egress/direct/transit modes to be used for this search. " +
"Note that this only works at the Line level. If individual ServiceJourneys have " +
"modes that differ from the Line mode, this will NOT be accounted for."
)
.type(ModeInputType.INPUT_TYPE)
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("banned")
.description("Banned")
.description(
"Parameters for indicating authorities, lines or quays not be used in the trip patterns"
)
.type(BannedInputType.INPUT_TYPE)
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("whiteListed")
.description(
"Parameters for indicating the only authorities, lines or quays to be used in the trip patterns"
)
.type(JourneyWhiteListed.INPUT_TYPE)
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("walkSpeed")
.description("The maximum walk speed along streets, in meters per second.")
.type(Scalars.GraphQLFloat)
.defaultValue(preferences.walk().speed())
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("walkReluctance")
.description(
"Walk cost is multiplied by this value. This is the main parameter to use for limiting walking."
)
.type(Scalars.GraphQLFloat)
.defaultValue(preferences.walk().reluctance())
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("waitReluctance")
.description(
"Wait cost is multiplied by this value. Setting this to a value lower than 1 " +
"indicates that waiting is better than staying on a vehicle. This should never " +
"be set higher than walkReluctance, since that would lead to walking down a line " +
"to avoid waiting."
)
.type(Scalars.GraphQLFloat)
.defaultValue(preferences.transfer().waitReluctance())
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("bikeSpeed")
.description("The maximum bike speed along streets, in meters per second")
.type(Scalars.GraphQLFloat)
.defaultValue(preferences.bike().speed())
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("bicycleOptimisationMethod")
.description(
"The set of characteristics that the user wants to optimise for during bicycle " +
"searches -- defaults to " +
enumValAsString(
EnumTypes.BICYCLE_OPTIMISATION_METHOD,
preferences.bike().optimizeType()
)
)
.type(EnumTypes.BICYCLE_OPTIMISATION_METHOD)
.defaultValue(preferences.bike().optimizeType())
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("triangleFactors")
.description(
"When setting the " +
EnumTypes.BICYCLE_OPTIMISATION_METHOD.getName() +
" to '" +
enumValAsString(EnumTypes.BICYCLE_OPTIMISATION_METHOD, BicycleOptimizeType.TRIANGLE) +
"', use these values to tell the routing engine how important each of the factors is compared to the others. All values should add up to 1."
)
.type(TriangleFactorsInputType.INPUT_TYPE)
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("useBikeRentalAvailabilityInformation")
.description(
"Whether or not bike rental availability information will be used to plan bike " +
"rental trips."
)
.type(Scalars.GraphQLBoolean)
.defaultValue(preferences.rental().useAvailabilityInformation())
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("transferPenalty")
.description(
"An extra penalty added on transfers (i.e. all boardings except the first one). " +
"The transferPenalty is used when a user requests even less transfers. In the " +
"latter case, we don't actually optimise for fewest transfers, as this can lead " +
"to absurd results. Consider a trip in New York from Grand Army Plaza (the one " +
"in Brooklyn) to Kalustyan's at noon. The true lowest transfers trip pattern is " +
"to wait until midnight, when the 4 train runs local the whole way. The actual " +
"fastest trip pattern is the 2/3 to the 4/5 at Nevins to the 6 at Union Square, " +
"which takes half an hour. Even someone optimise for fewest transfers doesn't " +
"want to wait until midnight. Maybe they would be willing to walk to 7th Ave " +
"and take the Q to Union Square, then transfer to the 6. If this takes less than " +
"transferPenalty seconds, then that's what we'll return."
)
.type(Scalars.GraphQLInt)
.defaultValue(preferences.transfer().cost())
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("transferSlack")
.description(
"An expected transfer time (in seconds) that specifies the amount of time that " +
"must pass between exiting one public transport vehicle and boarding another. " +
"This time is in addition to time it might take to walk between stops."
)
.type(Scalars.GraphQLInt)
.defaultValue(preferences.transfer().slack())
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("boardSlackDefault")
.description(TransportModeSlack.boardSlackDescription("boardSlackList"))
.type(Scalars.GraphQLInt)
.defaultValue(preferences.transit().boardSlack().defaultValueSeconds())
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("boardSlackList")
.description(
TransportModeSlack.slackByGroupDescription(
"boardSlack",
preferences.transit().boardSlack()
)
)
.type(TransportModeSlack.SLACK_LIST_INPUT_TYPE)
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("alightSlackDefault")
.description(TransportModeSlack.alightSlackDescription("alightSlackList"))
.type(Scalars.GraphQLInt)
.defaultValue(preferences.transit().alightSlack().defaultValueSeconds())
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("alightSlackList")
.description(
TransportModeSlack.slackByGroupDescription(
"alightSlack",
preferences.transit().alightSlack()
)
)
.type(TransportModeSlack.SLACK_LIST_INPUT_TYPE)
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("numTripPatterns")
.description(
"The maximum number of trip patterns to return. Note! This reduce the number of " +
"trip patterns AFTER the OTP travel search is done in a post-filtering process. " +
"There is little performance gain in reducing the number of trip patterns " +
"returned. The post-filtering will reduce the number of trip-patterns down to " +
"this size. It does not make the search faster, as it did in OTP1. See also the " +
"trip meta-data on how to implement paging."
)
.defaultValue(routing.request.numItineraries())
.type(Scalars.GraphQLInt)
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("maximumTransfers")
.description(
"Maximum number of transfers. Note! The best way to reduce the number of " +
"transfers is to set the `transferPenalty` parameter."
)
.type(Scalars.GraphQLInt)
.defaultValue(preferences.transfer().maxTransfers())
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("debugItineraryFilter")
.description(
"Debug the itinerary-filter-chain. OTP will attach a system notice to itineraries " +
"instead of removing them. This is very convenient when tuning the filters."
)
.type(Scalars.GraphQLBoolean)
.defaultValue(preferences.itineraryFilter().debug())
.build()
)
.argument(
GraphQLArgument
.newArgument()
.name("itineraryFilters")
.description(
"Configure the itinerary-filter-chain. NOTE! THESE PARAMETERS ARE USED " +
"FOR SERVER-SIDE TUNING AND IS AVAILABLE HERE FOR TESTING ONLY."
)
.type(ItineraryFiltersInputType.create(gqlUtil, preferences.itineraryFilter()))
.build()
)
.dataFetcher(environment -> new TransmodelGraphQLPlanner().plan(environment))
.build();
}
@SuppressWarnings("OptionalGetWithoutIsPresent")
private static String enumValAsString(GraphQLEnumType enumType, Enum> otpVal) {
return enumType
.getValues()
.stream()
.filter(e -> e.getValue().equals(otpVal))
.findFirst()
.get()
.getName();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy