/* * 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.routing.lm; import com.graphhopper.routing.*; import com.graphhopper.routing.util.AbstractAlgoPreparation; import com.graphhopper.routing.util.TraversalMode; import com.graphhopper.routing.util.spatialrules.Polygon; import com.graphhopper.routing.util.spatialrules.SpatialRuleLookup; import com.graphhopper.routing.weighting.Weighting; import com.graphhopper.storage.Directory; import com.graphhopper.storage.Graph; import com.graphhopper.storage.GraphHopperStorage; import com.graphhopper.util.Helper; import com.graphhopper.util.Parameters; import com.graphhopper.util.Parameters.Landmark; import com.graphhopper.util.StopWatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; import java.util.Map; /** * This class does the preprocessing for the ALT algorithm (A* , landmark, triangle inequality). * <p> * http://www.siam.org/meetings/alenex05/papers/03agoldberg.pdf * * @author Peter Karich */ public class PrepareLandmarks extends AbstractAlgoPreparation { private static final Logger LOGGER = LoggerFactory.getLogger(PrepareLandmarks.class); private final Graph graph; private final LandmarkStorage lms; private final Weighting weighting; private int defaultActiveLandmarks; public PrepareLandmarks(Directory dir, GraphHopperStorage graph, Weighting weighting, TraversalMode traversalMode, int landmarks, int activeLandmarks) { if (activeLandmarks > landmarks) throw new IllegalArgumentException("Default value for active landmarks " + activeLandmarks + " should be less or equal to landmark count of " + landmarks); this.graph = graph; this.defaultActiveLandmarks = activeLandmarks; this.weighting = weighting; lms = new LandmarkStorage(graph, dir, landmarks, weighting, traversalMode); } /** * @see LandmarkStorage#setLandmarkSuggestions(List) */ public PrepareLandmarks setLandmarkSuggestions(List<LandmarkSuggestion> landmarkSuggestions) { lms.setLandmarkSuggestions(landmarkSuggestions); return this; } /** * @see LandmarkStorage#setSpatialRuleLookup(SpatialRuleLookup) */ public PrepareLandmarks setSpatialRuleLookup(SpatialRuleLookup ruleLookup) { lms.setSpatialRuleLookup(ruleLookup); return this; } /** * @see LandmarkStorage#setMaximumWeight(double) */ public PrepareLandmarks setMaximumWeight(double maximumWeight) { lms.setMaximumWeight(maximumWeight); return this; } /** * @see LandmarkStorage#setLMSelectionWeighting(Weighting) */ public void setLMSelectionWeighting(Weighting w) { lms.setLMSelectionWeighting(w); } /** * @see LandmarkStorage#setMinimumNodes(int) */ public void setMinimumNodes(int nodes) { if (nodes < 2) throw new IllegalArgumentException("minimum node count must be at least 2"); lms.setMinimumNodes(nodes); } LandmarkStorage getLandmarkStorage() { return lms; } public int getSubnetworksWithLandmarks() { return lms.getSubnetworksWithLandmarks(); } public Weighting getWeighting() { return weighting; } public boolean loadExisting() { return lms.loadExisting(); } @Override public void doWork() { super.doWork(); StopWatch sw = new StopWatch().start(); LOGGER.info("Start calculating " + lms.getLandmarkCount() + " landmarks, default active lms:" + defaultActiveLandmarks + ", weighting:" + lms.getLmSelectionWeighting() + ", " + Helper.getMemInfo()); lms.createLandmarks(); lms.flush(); LOGGER.info("Calculating landmarks for " + (lms.getSubnetworksWithLandmarks() - 1) + " subnetworks took:" + sw.stop().getSeconds() + " => " + lms.getLandmarksAsGeoJSON() + ", stored weights:" + lms.getLandmarkCount() + ", nodes:" + graph.getNodes() + ", " + Helper.getMemInfo()); } public RoutingAlgorithm getDecoratedAlgorithm(Graph qGraph, RoutingAlgorithm algo, AlgorithmOptions opts) { int activeLM = Math.max(1, opts.getHints().getInt(Landmark.ACTIVE_COUNT, defaultActiveLandmarks)); if (algo instanceof AStar) { if (!lms.isInitialized()) throw new IllegalStateException("Initalize landmark storage before creating algorithms"); double epsilon = opts.getHints().getDouble(Parameters.Algorithms.ASTAR + ".epsilon", 1); AStar astar = (AStar) algo; astar.setApproximation(new LMApproximator(qGraph, this.graph.getNodes(), lms, activeLM, lms.getFactor(), false). setEpsilon(epsilon)); return algo; } else if (algo instanceof AStarBidirection) { if (!lms.isInitialized()) throw new IllegalStateException("Initalize landmark storage before creating algorithms"); double epsilon = opts.getHints().getDouble(Parameters.Algorithms.ASTAR_BI + ".epsilon", 1); AStarBidirection astarbi = (AStarBidirection) algo; astarbi.setApproximation(new LMApproximator(qGraph, this.graph.getNodes(), lms, activeLM, lms.getFactor(), false). setEpsilon(epsilon)); return algo; } else if (algo instanceof AlternativeRoute) { if (!lms.isInitialized()) throw new IllegalStateException("Initalize landmark storage before creating algorithms"); double epsilon = opts.getHints().getDouble(Parameters.Algorithms.ASTAR_BI + ".epsilon", 1); AlternativeRoute altRoute = (AlternativeRoute) algo; altRoute.setApproximation(new LMApproximator(qGraph, this.graph.getNodes(), lms, activeLM, lms.getFactor(), false). setEpsilon(epsilon)); // landmark algorithm follows good compromise between fast response and exploring 'interesting' paths so we // can decrease this exploration factor further (1->dijkstra, 0.8->bidir. A*) altRoute.setMaxExplorationFactor(0.6); } return algo; } }