com.graphhopper.gtfs.PtRouterImpl Maven / Gradle / Ivy
The newest version!
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.gtfs;
import com.conveyal.gtfs.GTFSFeed;
import com.google.transit.realtime.GtfsRealtime;
import com.graphhopper.GHResponse;
import com.graphhopper.GraphHopperConfig;
import com.graphhopper.ResponsePath;
import com.graphhopper.config.Profile;
import com.graphhopper.routing.DefaultWeightingFactory;
import com.graphhopper.routing.WeightingFactory;
import com.graphhopper.routing.ev.Subnetwork;
import com.graphhopper.routing.querygraph.QueryGraph;
import com.graphhopper.routing.util.DefaultSnapFilter;
import com.graphhopper.routing.util.EdgeFilter;
import com.graphhopper.routing.util.EncodingManager;
import com.graphhopper.routing.weighting.Weighting;
import com.graphhopper.storage.BaseGraph;
import com.graphhopper.storage.index.LocationIndex;
import com.graphhopper.util.*;
import com.graphhopper.util.details.PathDetailsBuilderFactory;
import com.graphhopper.util.exceptions.ConnectionNotFoundException;
import com.graphhopper.util.exceptions.MaximumNodesExceededException;
import javax.inject.Inject;
import java.time.Instant;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static java.util.Comparator.comparingLong;
public final class PtRouterImpl implements PtRouter {
private final GraphHopperConfig config;
private final TranslationMap translationMap;
private final BaseGraph baseGraph;
private final EncodingManager encodingManager;
private final LocationIndex locationIndex;
private final GtfsStorage gtfsStorage;
private final PtGraph ptGraph;
private final RealtimeFeed realtimeFeed;
private final PathDetailsBuilderFactory pathDetailsBuilderFactory;
private final WeightingFactory weightingFactory;
@Inject
public PtRouterImpl(GraphHopperConfig config, TranslationMap translationMap, BaseGraph baseGraph, EncodingManager encodingManager, LocationIndex locationIndex, GtfsStorage gtfsStorage, RealtimeFeed realtimeFeed, PathDetailsBuilderFactory pathDetailsBuilderFactory) {
this.config = config;
this.weightingFactory = new DefaultWeightingFactory(baseGraph, encodingManager);
this.translationMap = translationMap;
this.baseGraph = baseGraph;
this.encodingManager = encodingManager;
this.locationIndex = locationIndex;
this.gtfsStorage = gtfsStorage;
this.ptGraph = gtfsStorage.getPtGraph();
this.realtimeFeed = realtimeFeed;
this.pathDetailsBuilderFactory = pathDetailsBuilderFactory;
}
@Override
public GHResponse route(Request request) {
return new RequestHandler(request).route();
}
public static class Factory {
private final GraphHopperConfig config;
private final TranslationMap translationMap;
private final BaseGraph baseGraph;
private final EncodingManager encodingManager;
private final LocationIndex locationIndex;
private final GtfsStorage gtfsStorage;
private final Map transfers;
public Factory(GraphHopperConfig config, TranslationMap translationMap, BaseGraph baseGraph, EncodingManager encodingManager, LocationIndex locationIndex, GtfsStorage gtfsStorage) {
this.config = config;
this.translationMap = translationMap;
this.baseGraph = baseGraph;
this.encodingManager = encodingManager;
this.locationIndex = locationIndex;
this.gtfsStorage = gtfsStorage;
this.transfers = new HashMap<>();
for (Map.Entry entry : this.gtfsStorage.getGtfsFeeds().entrySet()) {
this.transfers.put(entry.getKey(), new Transfers(entry.getValue()));
}
}
public PtRouter createWith(GtfsRealtime.FeedMessage realtimeFeed) {
Map realtimeFeeds = new HashMap<>();
realtimeFeeds.put("gtfs_0", realtimeFeed);
return new PtRouterImpl(config, translationMap, baseGraph, encodingManager, locationIndex, gtfsStorage, RealtimeFeed.fromProtobuf(gtfsStorage, this.transfers, realtimeFeeds), new PathDetailsBuilderFactory());
}
public PtRouter createWithoutRealtimeFeed() {
return new PtRouterImpl(config, translationMap, baseGraph, encodingManager, locationIndex, gtfsStorage, RealtimeFeed.empty(), new PathDetailsBuilderFactory());
}
}
private class RequestHandler {
private final int maxVisitedNodesForRequest;
private final int limitSolutions;
private final long maxProfileDuration;
private final Instant initialTime;
private final boolean profileQuery;
private final boolean arriveBy;
private final boolean ignoreTransfers;
private final double betaTransfers;
private final double betaAccessTime;
private final double betaEgressTime;
private final double walkSpeedKmH;
private final int blockedRouteTypes;
private final Map transferPenaltiesByRouteType;
private final GHLocation enter;
private final GHLocation exit;
private final Translation translation;
private final List requestedPathDetails;
private final GHResponse response = new GHResponse();
private final long limitTripTime;
private final long limitStreetTime;
private QueryGraph queryGraph;
private int visitedNodes;
private MultiCriteriaLabelSetting router;
private final Profile accessProfile;
private final EdgeFilter accessSnapFilter;
private final Weighting accessWeighting;
private final Profile transferProfile;
private final Weighting transferWeighting;
private final Profile egressProfile;
private final EdgeFilter egressSnapFilter;
private final Weighting egressWeighting;
RequestHandler(Request request) {
maxVisitedNodesForRequest = request.getMaxVisitedNodes();
profileQuery = request.isProfileQuery();
ignoreTransfers = Optional.ofNullable(request.getIgnoreTransfers()).orElse(request.isProfileQuery());
betaTransfers = request.getBetaTransfers();
betaAccessTime = request.getBetaAccessTime();
betaEgressTime = request.getBetaEgressTime();
limitSolutions = Optional.ofNullable(request.getLimitSolutions()).orElse(profileQuery ? 50 : ignoreTransfers ? 1 : Integer.MAX_VALUE);
initialTime = request.getEarliestDepartureTime();
maxProfileDuration = request.getMaxProfileDuration().toMillis();
arriveBy = request.isArriveBy();
walkSpeedKmH = request.getWalkSpeedKmH();
blockedRouteTypes = request.getBlockedRouteTypes();
transferPenaltiesByRouteType = request.getBoardingPenaltiesByRouteType();
translation = translationMap.getWithFallBack(request.getLocale());
enter = request.getPoints().get(0);
exit = request.getPoints().get(1);
limitTripTime = request.getLimitTripTime() != null ? request.getLimitTripTime().toMillis() : Long.MAX_VALUE;
limitStreetTime = request.getLimitStreetTime() != null ? request.getLimitStreetTime().toMillis() : Long.MAX_VALUE;
requestedPathDetails = request.getPathDetails();
accessProfile = config.getProfiles().stream().filter(p -> p.getName().equals(request.getAccessProfile())).findFirst().get();
accessWeighting = weightingFactory.createWeighting(accessProfile, new PMap(), false);
accessSnapFilter = new DefaultSnapFilter(accessWeighting, encodingManager.getBooleanEncodedValue(Subnetwork.key(accessProfile.getName())));
transferProfile = config.getProfiles().stream().filter(p -> p.getName().equals("foot")).findFirst().get();
transferWeighting = weightingFactory.createWeighting(transferProfile, new PMap(), false);
egressProfile = config.getProfiles().stream().filter(p -> p.getName().equals(request.getEgressProfile())).findFirst().get();
egressWeighting = weightingFactory.createWeighting(egressProfile, new PMap(), false);
egressSnapFilter = new DefaultSnapFilter(egressWeighting, encodingManager.getBooleanEncodedValue(Subnetwork.key(egressProfile.getName())));
}
GHResponse route() {
StopWatch stopWatch = new StopWatch().start();
PtLocationSnapper.Result result = new PtLocationSnapper(baseGraph, locationIndex, gtfsStorage).snapAll(Arrays.asList(enter, exit), Arrays.asList(accessSnapFilter, egressSnapFilter));
queryGraph = result.queryGraph;
response.addDebugInfo("idLookup:" + stopWatch.stop().getSeconds() + "s");
Label.NodeId startNode;
Label.NodeId destNode;
if (arriveBy) {
startNode = result.nodes.get(1);
destNode = result.nodes.get(0);
} else {
startNode = result.nodes.get(0);
destNode = result.nodes.get(1);
}
List> solutions = findPaths(startNode, destNode);
parseSolutionsAndAddToResponse(solutions, result.points);
return response;
}
private void parseSolutionsAndAddToResponse(List> solutions, PointList waypoints) {
TripFromLabel tripFromLabel = new TripFromLabel(queryGraph, encodingManager, gtfsStorage, realtimeFeed, pathDetailsBuilderFactory, walkSpeedKmH);
for (List solution : solutions) {
final ResponsePath responsePath = tripFromLabel.createResponsePath(translation, waypoints, queryGraph, accessWeighting, egressWeighting, transferWeighting, solution, requestedPathDetails);
responsePath.setImpossible(solution.stream().anyMatch(t -> t.label.impossible));
responsePath.setTime((solution.get(solution.size() - 1).label.currentTime - solution.get(0).label.currentTime));
responsePath.setRouteWeight(router.weight(solution.get(solution.size() - 1).label));
response.add(responsePath);
}
Comparator c = Comparator.comparingInt(p -> (p.isImpossible() ? 1 : 0));
Comparator d = Comparator.comparingDouble(ResponsePath::getTime);
response.getAll().sort(c.thenComparing(d));
}
private List> findPaths(Label.NodeId startNode, Label.NodeId destNode) {
StopWatch stopWatch = new StopWatch().start();
boolean isEgress = !arriveBy;
final GraphExplorer accessEgressGraphExplorer = new GraphExplorer(queryGraph, ptGraph, isEgress ? egressWeighting : accessWeighting, gtfsStorage, realtimeFeed, isEgress, true, false, walkSpeedKmH, false, blockedRouteTypes);
GtfsStorage.EdgeType edgeType = isEgress ? GtfsStorage.EdgeType.EXIT_PT : GtfsStorage.EdgeType.ENTER_PT;
MultiCriteriaLabelSetting stationRouter = new MultiCriteriaLabelSetting(accessEgressGraphExplorer, isEgress, false, false, maxProfileDuration, new ArrayList<>());
stationRouter.setBetaStreetTime(isEgress ? betaEgressTime : betaAccessTime);
stationRouter.setLimitStreetTime(limitStreetTime);
List