ORSGraphHopper.java
/* This file is part of Openrouteservice.
*
* Openrouteservice is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License along with this library;
* if not, see <https://www.gnu.org/licenses/>.
*/
package org.heigit.ors.routing.graphhopper.extensions;
import com.graphhopper.*;
import com.graphhopper.config.CHProfile;
import com.graphhopper.config.LMProfile;
import com.graphhopper.config.Profile;
import com.graphhopper.gtfs.GraphHopperGtfs;
import com.graphhopper.reader.osm.OSMReader;
import com.graphhopper.routing.Router;
import com.graphhopper.routing.RouterConfig;
import com.graphhopper.routing.WeightingFactory;
import com.graphhopper.routing.ch.CHPreparationHandler;
import com.graphhopper.routing.lm.LMConfig;
import com.graphhopper.routing.lm.LMPreparationHandler;
import com.graphhopper.routing.lm.LandmarkStorage;
import com.graphhopper.routing.lm.PrepareLandmarks;
import com.graphhopper.routing.util.EdgeFilter;
import com.graphhopper.routing.util.FlagEncoder;
import com.graphhopper.routing.weighting.Weighting;
import com.graphhopper.storage.CHConfig;
import com.graphhopper.storage.GraphHopperStorage;
import com.graphhopper.storage.RoutingCHGraph;
import com.graphhopper.storage.index.LocationIndex;
import com.graphhopper.storage.index.Snap;
import com.graphhopper.util.*;
import com.graphhopper.util.details.PathDetailsBuilderFactory;
import com.graphhopper.util.exceptions.ConnectionNotFoundException;
import org.geotools.feature.SchemaException;
import org.heigit.ors.common.TravelRangeType;
import org.heigit.ors.fastisochrones.Contour;
import org.heigit.ors.fastisochrones.Eccentricity;
import org.heigit.ors.fastisochrones.partitioning.FastIsochroneFactory;
import org.heigit.ors.fastisochrones.partitioning.storage.CellStorage;
import org.heigit.ors.fastisochrones.partitioning.storage.IsochroneNodeStorage;
import org.heigit.ors.routing.AvoidFeatureFlags;
import org.heigit.ors.routing.RouteSearchContext;
import org.heigit.ors.routing.RouteSearchParameters;
import org.heigit.ors.routing.graphhopper.extensions.core.*;
import org.heigit.ors.routing.graphhopper.extensions.edgefilters.AvoidFeaturesEdgeFilter;
import org.heigit.ors.routing.graphhopper.extensions.edgefilters.EdgeFilterSequence;
import org.heigit.ors.routing.graphhopper.extensions.edgefilters.HeavyVehicleEdgeFilter;
import org.heigit.ors.routing.graphhopper.extensions.edgefilters.core.LMEdgeFilterSequence;
import org.heigit.ors.routing.graphhopper.extensions.flagencoders.FlagEncoderNames;
import org.heigit.ors.routing.graphhopper.extensions.storages.BordersGraphStorage;
import org.heigit.ors.routing.graphhopper.extensions.storages.GraphStorageUtils;
import org.heigit.ors.routing.graphhopper.extensions.storages.HeavyVehicleAttributesGraphStorage;
import org.heigit.ors.routing.graphhopper.extensions.storages.TrafficGraphStorage;
import org.heigit.ors.routing.graphhopper.extensions.storages.builders.GraphStorageBuilder;
import org.heigit.ors.routing.graphhopper.extensions.storages.builders.HereTrafficGraphStorageBuilder;
import org.heigit.ors.routing.graphhopper.extensions.util.ORSParameters;
import org.heigit.ors.routing.graphhopper.extensions.weighting.HgvAccessWeighting;
import org.heigit.ors.routing.pathprocessors.BordersExtractor;
import org.heigit.ors.util.CoordTools;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LineString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import static java.util.Collections.emptyList;
public class ORSGraphHopper extends GraphHopperGtfs {
private static final Logger LOGGER = LoggerFactory.getLogger(ORSGraphHopper.class);
public static final String KEY_DEPARTURE = "departure";
public static final String KEY_ARRIVAL = "arrival";
private GraphProcessContext processContext;
private HashMap<Long, ArrayList<Integer>> osmId2EdgeIds; // one osm id can correspond to multiple edges
private HashMap<Integer, Long> tmcEdges;
private Eccentricity eccentricity;
private int minNetworkSize = 200;
private final CorePreparationHandler corePreparationHandler = new CorePreparationHandler();
private final CoreLMPreparationHandler coreLMPreparationHandler = new CoreLMPreparationHandler();
private final FastIsochroneFactory fastIsochroneFactory = new FastIsochroneFactory();
public GraphHopperConfig getConfig() {
return config;
}
private GraphHopperConfig config;
public ORSGraphHopper(GraphProcessContext procCntx) {
processContext = procCntx;
processContext.init(this);
}
public ORSGraphHopper() {
// used to initialize tests more easily without the need to create GraphProcessContext etc. when they're anyway not used in the tested functions.
}
@Override
public GraphHopper init(GraphHopperConfig ghConfig) {
GraphHopper ret = super.init(ghConfig);
if (ghConfig instanceof ORSGraphHopperConfig orsConfig) {
corePreparationHandler.init(orsConfig);
coreLMPreparationHandler.init(orsConfig);
}
fastIsochroneFactory.init(ghConfig);
minNetworkSize = ghConfig.getInt("prepare.min_network_size", minNetworkSize);
config = ghConfig;
return ret;
}
@Override
protected void cleanUp() {
if (LOGGER.isInfoEnabled())
LOGGER.info("call cleanUp for '%s' ".formatted(getGraphHopperLocation()));
GraphHopperStorage ghs = getGraphHopperStorage();
if (ghs != null) {
if (LOGGER.isInfoEnabled())
LOGGER.info("graph %s, details:%s".formatted(ghs, ghs.toDetailsString()));
int prevNodeCount = ghs.getNodes();
int ex = ghs.getAllEdges().length();
List<FlagEncoder> list = getEncodingManager().fetchEdgeEncoders();
if (LOGGER.isDebugEnabled())
LOGGER.debug("will create PrepareRoutingSubnetworks with: NodeCountBefore: '%d' getAllEdges().getMaxId(): '%d' List<FlagEncoder>: '%s' minNetworkSize: '%d'".formatted(prevNodeCount, ex, list, minNetworkSize)
);
ghs.getProperties().put("elevation", hasElevation());
} else {
LOGGER.info("graph GraphHopperStorage is null?!");
}
super.cleanUp();
}
@Override
protected OSMReader createOSMReader() {
return new ORSOSMReader(getGraphHopperStorage(), processContext);
}
@Override
public GraphHopper importOrLoad() {
GraphHopper gh = super.importOrLoad();
if ((tmcEdges != null) && (osmId2EdgeIds != null)) {
java.nio.file.Path path = Paths.get(gh.getGraphHopperLocation(), "edges_ors_traffic");
if ((tmcEdges.size() == 0) || (osmId2EdgeIds.size() == 0)) {
// try to load TMC edges from file.
File file = path.toFile();
if (file.exists()) {
try (FileInputStream fis = new FileInputStream(path.toString());
ObjectInputStream ois = new ObjectInputStream(fis)) {
tmcEdges = (HashMap<Integer, Long>) ois.readObject();
osmId2EdgeIds = (HashMap<Long, ArrayList<Integer>>) ois.readObject();
LOGGER.info("Serialized HashMap data is saved in trafficEdges");
} catch (IOException ioe) {
LOGGER.error(Arrays.toString(ioe.getStackTrace()));
} catch (ClassNotFoundException c) {
LOGGER.error("Class not found");
LOGGER.error(Arrays.toString(c.getStackTrace()));
}
}
} else {
// save TMC edges if needed.
try (FileOutputStream fos = new FileOutputStream(path.toString());
ObjectOutputStream oos = new ObjectOutputStream(fos)) {
oos.writeObject(tmcEdges);
oos.writeObject(osmId2EdgeIds);
LOGGER.info("Serialized HashMap data is saved in trafficEdges");
} catch (IOException ioe) {
LOGGER.error(Arrays.toString(ioe.getStackTrace()));
}
}
}
return gh;
}
@Override
protected Router doCreateRouter(GraphHopperStorage ghStorage, LocationIndex locationIndex, Map<String, Profile> profilesByName,
PathDetailsBuilderFactory pathBuilderFactory, TranslationMap trMap, RouterConfig routerConfig,
WeightingFactory weightingFactory, Map<String, RoutingCHGraph> chGraphs, Map<String, LandmarkStorage> landmarks) {
ORSRouter r = new ORSRouter(ghStorage, locationIndex, profilesByName, pathBuilderFactory, trMap, routerConfig, weightingFactory, chGraphs, landmarks);
r.setEdgeFilterFactory(new ORSEdgeFilterFactory());
r.setPathProcessorFactory(pathProcessorFactory);
if (!(ghStorage instanceof ORSGraphHopperStorage))
throw new IllegalStateException("Expected an instance of ORSGraphHopperStorage");
Map<String, RoutingCHGraph> coreGraphs = new LinkedHashMap<>();
for (com.graphhopper.config.CHProfile chProfile : corePreparationHandler.getCHProfiles()) {
String chGraphName = corePreparationHandler.getPreparation(chProfile.getProfile()).getCHConfig().getName();
coreGraphs.put(chProfile.getProfile(), ((ORSGraphHopperStorage) ghStorage).getCoreGraph(chGraphName));
}
r.setCoreGraphs(coreGraphs);
Map<String, PrepareCoreLandmarks> coreLandmarks = new LinkedHashMap<>();
for (PrepareLandmarks preparation : coreLMPreparationHandler.getPreparations()) {
coreLandmarks.put(preparation.getLMConfig().getName(), (PrepareCoreLandmarks) preparation);
}
r.setCoreLandmarks(coreLandmarks);
return r;
}
@Override
protected WeightingFactory createWeightingFactory() {
return new ORSWeightingFactory(getGraphHopperStorage(), getEncodingManager());
}
/**
* Check whether the route processing has to start. If avoid all borders is set and the routing points are in different countries,
* there is no need to even start routing.
*
* @param request To get the avoid borders setting
* @param queryResult To get the edges of the queries and check which country they're in
*/
private void checkAvoidBorders(GHRequest request, List<Snap> queryResult) {
/* Avoid borders */
PMap params = request.getAdditionalHints();
if (params == null) {
params = new PMap();
}
boolean isRouteable = true;
if (params.has("avoid_borders")) {
RouteSearchParameters routeSearchParameters = params.getObject("avoid_borders", new RouteSearchParameters());
//Avoiding All borders
if (routeSearchParameters.hasAvoidBorders() && routeSearchParameters.getAvoidBorders() == BordersExtractor.Avoid.ALL) {
List<Integer> edgeIds = new ArrayList<>();
for (int placeIndex = 0; placeIndex < queryResult.size(); placeIndex++) {
edgeIds.add(queryResult.get(placeIndex).getClosestEdge().getEdge());
}
BordersExtractor bordersExtractor = new BordersExtractor(GraphStorageUtils.getGraphExtension(getGraphHopperStorage(), BordersGraphStorage.class), null);
isRouteable = bordersExtractor.isSameCountry(edgeIds);
}
//TODO Refactoring : Avoiding CONTROLLED borders
//Currently this is extremely messy, as for some reason the READER stores data in addition to the BordersStorage.
//At the same time, it is not possible to get isOpen from the Reader via ids, because it only takes Strings. But there are no Strings in the Storage.
//So no controlled borders for now until this whole thing is refactored and the Reader is an actual reader and not a storage.
// if(routeSearchParameters.hasAvoidBorders() && routeSearchParameters.getAvoidBorders() == BordersExtractor.Avoid.CONTROLLED) {
// GraphStorageBuilder countryBordersReader;
// if(processContext.getStorageBuilders().size() > 0) {
// countryBordersReader = processContext.getStorageBuilders().get(0);
// int i = 1;
// while (i < processContext.getStorageBuilders().size() && !(countryBordersReader instanceof CountryBordersReader)) {
// countryBordersReader = processContext.getStorageBuilders().get(i);
// i++;
// }
//
// List<Integer> edgeIds = new ArrayList<>();
// for (int placeIndex = 0; placeIndex < queryResult.size(); placeIndex++) {
// edgeIds.add(queryResult.get(placeIndex).getClosestEdge().getEdge());
// }
// BordersExtractor bordersExtractor = new BordersExtractor(GraphStorageUtils.getGraphExtension(getGraphHopperStorage(), BordersGraphStorage.class), null);
// if (!bordersExtractor.isSameCountry(edgeIds)) {
// isRouteable == ((CountryBordersReader) countryBordersReader).isOpen(id0, id1)
// ...
// }
// }
// }
}
if (!isRouteable)
throw new ConnectionNotFoundException("Route not found due to avoiding borders", Collections.emptyMap());
}
public GHResponse constructFreeHandRoute(GHRequest request) {
LineString directRouteGeometry = constructFreeHandRouteGeometry(request);
ResponsePath directRoutePathWrapper = constructFreeHandRoutePathWrapper(directRouteGeometry);
GHResponse directRouteResponse = new GHResponse();
directRouteResponse.add(directRoutePathWrapper);
directRouteResponse.getHints().putObject("skipped_segment", true);
return directRouteResponse;
}
private ResponsePath constructFreeHandRoutePathWrapper(LineString lineString) {
ResponsePath responsePath = new ResponsePath();
PointList pointList = new PointList();
PointList startPointList = new PointList();
PointList endPointList = new PointList();
PointList wayPointList = new PointList();
Coordinate startCoordinate = lineString.getCoordinateN(0);
Coordinate endCoordinate = lineString.getCoordinateN(1);
double distance = CoordTools.calcDistHaversine(startCoordinate.x, startCoordinate.y, endCoordinate.x, endCoordinate.y);
pointList.add(lineString.getCoordinateN(0).x, lineString.getCoordinateN(0).y);
pointList.add(lineString.getCoordinateN(1).x, lineString.getCoordinateN(1).y);
wayPointList.add(lineString.getCoordinateN(0).x, lineString.getCoordinateN(0).y);
wayPointList.add(lineString.getCoordinateN(1).x, lineString.getCoordinateN(1).y);
startPointList.add(lineString.getCoordinateN(0).x, lineString.getCoordinateN(0).y);
endPointList.add(lineString.getCoordinateN(1).x, lineString.getCoordinateN(1).y);
Translation translation = new TranslationMap.TranslationHashMap(new Locale(""));
InstructionList instructions = new InstructionList(translation);
Instruction startInstruction = new Instruction(Instruction.REACHED_VIA, "free hand route", startPointList);
Instruction endInstruction = new Instruction(Instruction.FINISH, "end of free hand route", endPointList);
instructions.add(0, startInstruction);
instructions.add(1, endInstruction);
responsePath.setDistance(distance);
responsePath.setAscend(0.0);
responsePath.setDescend(0.0);
responsePath.setTime(0);
responsePath.setInstructions(instructions);
responsePath.setWaypoints(wayPointList);
responsePath.setPoints(pointList);
responsePath.setRouteWeight(0.0);
responsePath.setDescription(new ArrayList<>());
responsePath.setImpossible(false);
startInstruction.setDistance(distance);
startInstruction.setTime(0);
return responsePath;
}
private LineString constructFreeHandRouteGeometry(GHRequest request) {
Coordinate start = new Coordinate();
Coordinate end = new Coordinate();
start.x = request.getPoints().get(0).getLat();
start.y = request.getPoints().get(0).getLon();
end.x = request.getPoints().get(1).getLat();
end.y = request.getPoints().get(1).getLon();
Coordinate[] coords = new Coordinate[]{start, end};
return new GeometryFactory().createLineString(coords);
}
private void matchTraffic() {
// Do the graph extension post-processing
// Reserved for processes that need a fully initiated graph e.g. for match making
if (getGraphHopperStorage() != null && processContext != null && processContext.getStorageBuilders() != null) {
for (GraphStorageBuilder graphStorageBuilder : processContext.getStorageBuilders()) {
if (graphStorageBuilder instanceof HereTrafficGraphStorageBuilder storageBuilder) {
try {
storageBuilder.postProcess(this);
} catch (SchemaException e) {
LOGGER.error("Error building the here traffic storage.");
throw new RuntimeException(e);
}
}
}
}
}
private void addTrafficSpeedCalculator(LMPreparationHandler lmPreparationHandler) {
if (isTrafficEnabled())
ORSWeightingFactory.addTrafficSpeedCalculator(lmPreparationHandler.getWeightings(), getGraphHopperStorage());
}
/**
* Does the preparation and creates the location index
*
* @param closeEarly release resources as early as possible
*/
@Override
protected void postProcessing(boolean closeEarly) {
super.postProcessing(closeEarly);
//Create the core
GraphHopperStorage gs = getGraphHopperStorage();
if (corePreparationHandler.isEnabled())
corePreparationHandler.setProcessContext(processContext).createPreparations(gs);
if (isCorePrepared()) {
// check loaded profiles
for (CHProfile profile : corePreparationHandler.getCHProfiles()) {
if (!getProfileVersion(profile.getProfile()).isEmpty() && !getProfileVersion(profile.getProfile()).equals("" + profilesByName.get(profile.getProfile()).getVersion()))
throw new IllegalArgumentException("Core preparation of " + profile.getProfile() + " already exists in storage and doesn't match configuration");
}
} else {
prepareCore(closeEarly);
}
//Create the landmarks in the core
if (coreLMPreparationHandler.isEnabled()) {
initCoreLMPreparationHandler();
coreLMPreparationHandler.createPreparations(gs, super.getLocationIndex());
addTrafficSpeedCalculator(coreLMPreparationHandler);
}
loadOrPrepareCoreLM();
if (fastIsochroneFactory.isEnabled()) {
EdgeFilterSequence partitioningEdgeFilter = new EdgeFilterSequence();
try {
partitioningEdgeFilter.add(new AvoidFeaturesEdgeFilter(AvoidFeatureFlags.FERRIES, getGraphHopperStorage()));
} catch (Exception e) {
LOGGER.debug(e.getLocalizedMessage());
}
fastIsochroneFactory.createPreparation(gs, partitioningEdgeFilter);
if (!isPartitionPrepared())
preparePartition();
else {
fastIsochroneFactory.setExistingStorages();
fastIsochroneFactory.getCellStorage().loadExisting();
fastIsochroneFactory.getIsochroneNodeStorage().loadExisting();
}
//No fast isochrones without partition
if (isPartitionPrepared()) {
// Initialize edge filter sequence for fast isochrones
calculateContours();
List<Profile> profiles = fastIsochroneFactory.getFastIsochroneProfiles();
for (Profile profile : profiles) {
Weighting weighting = ((ORSWeightingFactory) createWeightingFactory()).createIsochroneWeighting(profile);
for (FlagEncoder encoder : super.getEncodingManager().fetchEdgeEncoders()) {
calculateCellProperties(weighting, partitioningEdgeFilter, encoder, fastIsochroneFactory.getIsochroneNodeStorage(), fastIsochroneFactory.getCellStorage());
}
}
}
}
}
@Override
protected void postProcessingHook() {
matchTraffic();
if (getLMPreparationHandler().isEnabled())
addTrafficSpeedCalculator(getLMPreparationHandler());
}
//TODO Refactoring : This is a duplication with code in RoutingProfile and should probably be moved to a status keeping class.
private boolean hasCHProfile(String profileName) {
return contains(getGraphHopperStorage().getCHGraphNames(), profileName);
}
private boolean hasCoreProfile(String profileName) {
if (getGraphHopperStorage() instanceof ORSGraphHopperStorage) {
List<String> profiles = ((ORSGraphHopperStorage) getGraphHopperStorage()).getCoreGraphNames();
return contains(profiles, profileName);
}
return false;
}
private boolean hasLMProfile(String profileName) {
List<String> profiles = getLMPreparationHandler().getLMConfigs().stream().map(LMConfig::getName).collect(Collectors.toList());
return contains(profiles, profileName);
}
private boolean contains(List<String> profiles, String profileName) {
for (String profile : profiles) {
if (profileName.equals(profile))
return true;
}
return false;
}
public final boolean isCoreEnabled() {
return corePreparationHandler.isEnabled();
}
public final CorePreparationHandler getCorePreparationHandler() {
return corePreparationHandler;
}
@Override
protected void initCHPreparationHandler() {
CHPreparationHandler chPreparationHandler = getCHPreparationHandler();
if (chPreparationHandler.hasCHConfigs()) {
return;
}
for (CHProfile chProfile : chPreparationHandler.getCHProfiles()) {
Profile profile = profilesByName.get(chProfile.getProfile());
Weighting weighting = createWeighting(profile, new PMap());
if (profile.getVehicle().equals(FlagEncoderNames.HEAVYVEHICLE)) {
HeavyVehicleAttributesGraphStorage hgvStorage = GraphStorageUtils.getGraphExtension(getGraphHopperStorage(), HeavyVehicleAttributesGraphStorage.class);
EdgeFilter hgvEdgeFilter = new HeavyVehicleEdgeFilter(HeavyVehicleAttributes.HGV, null, hgvStorage);
weighting = new HgvAccessWeighting(weighting, hgvEdgeFilter);
}
if (profile.isTurnCosts()) {
chPreparationHandler.addCHConfig(CHConfig.edgeBased(profile.getName(), weighting));
} else {
chPreparationHandler.addCHConfig(CHConfig.nodeBased(profile.getName(), weighting));
}
}
}
protected void loadORS() {
List<CHConfig> chConfigs;
if (corePreparationHandler.isEnabled()) {
initCorePreparationHandler();
chConfigs = corePreparationHandler.getCHConfigs();
} else {
chConfigs = emptyList();
}
if (getGraphHopperStorage() instanceof ORSGraphHopperStorage)
((ORSGraphHopperStorage) getGraphHopperStorage()).addCoreGraphs(chConfigs);
else
throw new IllegalStateException("Expected an instance of ORSGraphHopperStorage");
}
private void initCorePreparationHandler() {
if (corePreparationHandler.hasCHConfigs()) {
return;
}
for (com.graphhopper.config.CHProfile chProfile : corePreparationHandler.getCHProfiles()) {
Profile profile = profilesByName.get(chProfile.getProfile());
corePreparationHandler.addCHConfig(new CHConfig(profile.getName(), createWeighting(profile, new PMap()), profile.isTurnCosts(), CHConfig.TYPE_CORE));
}
}
private void initCoreLMPreparationHandler() {
if (coreLMPreparationHandler.hasLMProfiles())
return;
CoreLMOptions coreLMOptions = coreLMPreparationHandler.getCoreLMOptions();
coreLMOptions.createRestrictionFilters(getGraphHopperStorage());
for (LMProfile lmProfile : coreLMPreparationHandler.getLMProfiles()) {
if (lmProfile.usesOtherPreparation())
continue;
Profile profile = profilesByName.get(lmProfile.getProfile());
Weighting weighting = createWeighting(profile, new PMap(), true);
for (LMEdgeFilterSequence edgeFilter : coreLMOptions.getFilters()) {
CoreLMConfig coreLMConfig = new CoreLMConfig(profile.getName(), weighting);
coreLMConfig.setEdgeFilter(edgeFilter);
coreLMPreparationHandler.addLMConfig(coreLMConfig);
}
}
}
protected void prepareCore(boolean closeEarly) {
for (CHProfile profile : corePreparationHandler.getCHProfiles()) {
if (!getProfileVersion(profile.getProfile()).isEmpty()
&& !getProfileVersion(profile.getProfile()).equals("" + profilesByName.get(profile.getProfile()).getVersion()))
throw new IllegalArgumentException("Core preparation of " + profile.getProfile() + " already exists in storage and doesn't match configuration");
}
if (isCoreEnabled()) {
ensureWriteAccess();
GraphHopperStorage ghStorage = getGraphHopperStorage();
ghStorage.freeze();
corePreparationHandler.prepare(ghStorage.getProperties(), closeEarly);
ghStorage.getProperties().put(ORSParameters.Core.PREPARE + "done", true);
for (CHProfile profile : corePreparationHandler.getCHProfiles()) {
// potentially overwrite existing keys from CH/LM
setProfileVersion(profile.getProfile(), profilesByName.get(profile.getProfile()).getVersion());
}
}
}
private boolean isCorePrepared() {
return "true".equals(getGraphHopperStorage().getProperties().get(ORSParameters.Core.PREPARE + "done"))
// remove old property in >0.9
|| "true".equals(getGraphHopperStorage().getProperties().get("prepare.done"));
}
public final boolean isCoreLMEnabled() {
return coreLMPreparationHandler.isEnabled();
}
/**
* For landmarks it is required to always call this method: either it creates the landmark data or it loads it.
*/
protected void loadOrPrepareCoreLM() {
boolean tmpPrepare = coreLMPreparationHandler.isEnabled();
if (tmpPrepare) {
ensureWriteAccess();
getGraphHopperStorage().freeze();
if (coreLMPreparationHandler.loadOrDoWork(getGraphHopperStorage().getProperties(), false))
getGraphHopperStorage().getProperties().put(ORSParameters.CoreLandmark.PREPARE + "done", true);
}
}
//TODO Refactoring : This is a duplication with code in RoutingProfile and should probably be moved to a status keeping class.
public final boolean isCHAvailable(String profileName) {
return getCHPreparationHandler().isEnabled() && hasCHProfile(profileName);
}
public final boolean isLMAvailable(String profileName) {
return getLMPreparationHandler().isEnabled() && hasLMProfile(profileName);
}
public final boolean isCoreAvailable(String profileName) {
return getCorePreparationHandler().isEnabled() && hasCoreProfile(profileName);
}
public final boolean isFastIsochroneAvailable(RouteSearchContext searchContext, TravelRangeType travelRangeType) {
return eccentricity != null && eccentricity.isAvailable(ORSWeightingFactory.createIsochroneWeighting(searchContext, travelRangeType));
}
/**
* Partitioning
*/
public final FastIsochroneFactory getFastIsochroneFactory() {
return fastIsochroneFactory;
}
protected void preparePartition() {
if (fastIsochroneFactory.isEnabled()) {
ensureWriteAccess();
getGraphHopperStorage().freeze();
fastIsochroneFactory.prepare(getGraphHopperStorage().getProperties());
getGraphHopperStorage().getProperties().put(ORSParameters.FastIsochrone.PREPARE + "done", true);
}
}
private boolean isPartitionPrepared() {
return "true".equals(getGraphHopperStorage().getProperties().get(ORSParameters.FastIsochrone.PREPARE + "done"));
}
private void calculateContours() {
if (fastIsochroneFactory.getCellStorage().isContourPrepared())
return;
Contour contour = new Contour(getGraphHopperStorage(), getGraphHopperStorage().getNodeAccess(), fastIsochroneFactory.getIsochroneNodeStorage(), fastIsochroneFactory.getCellStorage());
contour.calculateContour();
}
private void calculateCellProperties(Weighting weighting, EdgeFilter edgeFilter, FlagEncoder flagEncoder, IsochroneNodeStorage isochroneNodeStorage, CellStorage cellStorage) {
if (eccentricity == null)
eccentricity = new Eccentricity(getGraphHopperStorage(), getLocationIndex(), isochroneNodeStorage, cellStorage);
if (!eccentricity.loadExisting(weighting)) {
eccentricity.calcEccentricities(weighting, edgeFilter, flagEncoder);
eccentricity.calcBorderNodeDistances(weighting, edgeFilter, flagEncoder);
}
}
public Eccentricity getEccentricity() {
return eccentricity;
}
public boolean isTrafficEnabled() {
return GraphStorageUtils.getGraphExtension(getGraphHopperStorage(), TrafficGraphStorage.class) != null;
}
public long getMemoryUsage() {
long mem = 0;
if (getLMPreparationHandler().isEnabled()) {
mem += getLMPreparationHandler().getPreparations().stream().mapToLong(lm -> lm.getLandmarkStorage().getCapacity()).sum();
}
if (isCoreEnabled()) {
// core CH preparations are handled in ORSGraphHopperStorage.getCapacity()
mem += coreLMPreparationHandler.getPreparations().stream().mapToLong(lm -> lm.getLandmarkStorage().getCapacity()).sum();
}
if (fastIsochroneFactory.isEnabled()) {
mem += fastIsochroneFactory.getCapacity();
}
return mem + getGraphHopperStorage().getCapacity();
}
}