org.opentripplanner.ext.transmodelapi.TransmodelGraphQLPlanner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of otp Show documentation
Show all versions of otp Show documentation
The OpenTripPlanner multimodal journey planning system
package org.opentripplanner.ext.transmodelapi;
import static org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper.mapIDsToDomain;
import graphql.GraphQLException;
import graphql.execution.DataFetcherResult;
import graphql.schema.DataFetchingEnvironment;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.DoubleFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.opentripplanner.api.common.ParameterException;
import org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper;
import org.opentripplanner.ext.transmodelapi.model.PlanResponse;
import org.opentripplanner.ext.transmodelapi.model.TransmodelTransportSubmode;
import org.opentripplanner.ext.transmodelapi.model.TransportModeSlack;
import org.opentripplanner.ext.transmodelapi.model.plan.ItineraryFiltersInputType;
import org.opentripplanner.ext.transmodelapi.support.DataFetcherDecorator;
import org.opentripplanner.ext.transmodelapi.support.GqlUtil;
import org.opentripplanner.model.FeedScopedId;
import org.opentripplanner.model.GenericLocation;
import org.opentripplanner.model.modes.AllowedTransitMode;
import org.opentripplanner.model.TransitMode;
import org.opentripplanner.routing.algorithm.mapping.TripPlanMapper;
import org.opentripplanner.routing.api.request.BannedStopSet;
import org.opentripplanner.routing.api.request.RequestModes;
import org.opentripplanner.routing.api.request.RoutingRequest;
import org.opentripplanner.routing.api.request.StreetMode;
import org.opentripplanner.routing.api.response.RoutingError;
import org.opentripplanner.routing.api.response.RoutingErrorCode;
import org.opentripplanner.routing.api.response.RoutingResponse;
import org.opentripplanner.routing.core.BicycleOptimizeType;
import org.opentripplanner.standalone.server.Router;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TransmodelGraphQLPlanner {
private static final Logger LOG = LoggerFactory.getLogger(TransmodelGraphQLPlanner.class);
public DataFetcherResult plan(DataFetchingEnvironment environment) {
PlanResponse response = new PlanResponse();
TransmodelRequestContext ctx = environment.getContext();
Router router = ctx.getRouter();
Locale locale = router.defaultRoutingRequest.locale;
RoutingRequest request = null;
try {
request = createRequest(environment);
locale = request.locale;
RoutingResponse res = ctx.getRoutingService().route(request, router);
response.plan = res.getTripPlan();
response.metadata = res.getMetadata();
response.messages = res.getRoutingErrors();
response.debugOutput = res.getDebugTimingAggregator().finishedRendering();
response.previousPageCursor = res.getPreviousPageCursor();
response.nextPageCursor = res.getNextPageCursor();
}
catch (ParameterException e) {
var msg = e.message.get();
throw new GraphQLException(msg, e);
}
catch (Exception e) {
LOG.error("System error: " + e.getMessage(), e);
response.plan = TripPlanMapper.mapTripPlan(request, List.of());
response.messages.add(new RoutingError(RoutingErrorCode.SYSTEM_ERROR, null));
}
return DataFetcherResult.newResult()
.data(response)
.localContext(Map.of("locale", locale))
.build();
}
private GenericLocation toGenericLocation(Map m) {
Map coordinates = (Map) m.get("coordinates");
Double lat = null;
Double lon = null;
if (coordinates != null) {
lat = (Double) coordinates.get("latitude");
lon = (Double) coordinates.get("longitude");
}
String placeRef = (String) m.get("place");
FeedScopedId stopId = placeRef == null ? null : TransitIdMapper.mapIDToDomain(placeRef);
String name = (String) m.get("name");
name = name == null ? "" : name;
return new GenericLocation(name, stopId, lat, lon);
}
private RoutingRequest createRequest(DataFetchingEnvironment environment)
throws ParameterException {
TransmodelRequestContext context = environment.getContext();
Router router = context.getRouter();
RoutingRequest request = router.defaultRoutingRequest.clone();
DataFetcherDecorator callWith = new DataFetcherDecorator(environment);
callWith.argument("locale", (String v) -> request.locale = Locale.forLanguageTag(v));
callWith.argument("from", (Map v) -> request.from = toGenericLocation(v));
callWith.argument("to", (Map v) -> request.to = toGenericLocation(v));
callWith.argument("dateTime", millisSinceEpoch -> request.setDateTime(Instant.ofEpochMilli((long)millisSinceEpoch)), Date::new);
callWith.argument("searchWindow", (Integer m) -> request.searchWindow = Duration.ofMinutes(m));
callWith.argument("pageCursor", request::setPageCursor);
callWith.argument("timetableView", (Boolean v) -> request.timetableView = v);
callWith.argument("wheelchair", request::setWheelchairAccessible);
callWith.argument("numTripPatterns", request::setNumItineraries);
callWith.argument("transitGeneralizedCostLimit", (DoubleFunction it) -> request.itineraryFilters.transitGeneralizedCostLimit = it);
// callWith.argument("maxTransferWalkDistance", request::setMaxTransferWalkDistance);
// callWith.argument("preTransitReluctance", (Double v) -> request.setPreTransitReluctance(v));
// callWith.argument("maxPreTransitWalkDistance", (Double v) -> request.setMaxPreTransitWalkDistance(v));
callWith.argument("walkBoardCost", request::setWalkBoardCost);
callWith.argument("walkReluctance", request::setNonTransitReluctance);
callWith.argument("waitReluctance", request::setWaitReluctance);
callWith.argument("walkBoardCost", request::setWalkBoardCost);
// callWith.argument("walkOnStreetReluctance", request::setWalkOnStreetReluctance);
callWith.argument("waitReluctance", request::setWaitReluctance);
callWith.argument("waitAtBeginningFactor", request::setWaitAtBeginningFactor);
callWith.argument("walkSpeed", (Double v) -> request.walkSpeed = v);
callWith.argument("bikeSpeed", (Double v) -> request.bikeSpeed = v);
callWith.argument("bikeSwitchTime", (Integer v) -> request.bikeSwitchTime = v);
callWith.argument("bikeSwitchCost", (Integer v) -> request.bikeSwitchCost = v);
// callWith.argument("transitDistanceReluctance", (Double v) -> request.transitDistanceReluctance = v);
BicycleOptimizeType bicycleOptimizeType = environment.getArgument("bicycleOptimisationMethod");
if (bicycleOptimizeType == BicycleOptimizeType.TRIANGLE) {
// Arguments: [ safety, slope, time ]
final double[] args = new double[3];
callWith.argument("triangleFactors.safety", (Double v) -> args[0] = v);
callWith.argument("triangleFactors.slope", (Double v) -> args[1] = v);
callWith.argument("triangleFactors.time", (Double v) -> args[2] = v);
request.setTriangleNormalized(args[0], args[1], args[2]);
}
if (bicycleOptimizeType == BicycleOptimizeType.TRANSFERS) {
bicycleOptimizeType = BicycleOptimizeType.QUICK;
request.transferCost += 1800;
}
if (bicycleOptimizeType != null) {
request.bicycleOptimizeType = bicycleOptimizeType;
}
callWith.argument("arriveBy", request::setArriveBy);
request.showIntermediateStops = true;
callWith.argument("vias", (List