From 0f5b7595d5ee8d684096e86bcc8e8c466a369554 Mon Sep 17 00:00:00 2001 From: Hendrik Leuschner Date: Mon, 7 Mar 2022 15:18:48 +0100 Subject: [PATCH 1/4] Integrate DijkstraMatrix into RoutingProfile matrix pipeline --- .../heigit/ors/routing/RoutingProfile.java | 126 ++++++++++++------ 1 file changed, 87 insertions(+), 39 deletions(-) diff --git a/openrouteservice/src/main/java/org/heigit/ors/routing/RoutingProfile.java b/openrouteservice/src/main/java/org/heigit/ors/routing/RoutingProfile.java index b77f6c265b..c261cc6206 100644 --- a/openrouteservice/src/main/java/org/heigit/ors/routing/RoutingProfile.java +++ b/openrouteservice/src/main/java/org/heigit/ors/routing/RoutingProfile.java @@ -49,8 +49,7 @@ import org.heigit.ors.mapmatching.RouteSegmentInfo; import org.heigit.ors.mapmatching.hmm.HiddenMarkovMapMatcher; import org.heigit.ors.matrix.*; -import org.heigit.ors.matrix.algorithms.MatrixAlgorithm; -import org.heigit.ors.matrix.algorithms.MatrixAlgorithmFactory; +import org.heigit.ors.matrix.algorithms.dijkstra.DijkstraMatrixAlgorithm; import org.heigit.ors.matrix.algorithms.rphast.RPHASTMatrixAlgorithm; import org.heigit.ors.routing.configuration.RouteProfileConfiguration; import org.heigit.ors.routing.graphhopper.extensions.*; @@ -404,6 +403,15 @@ private boolean hasCHProfile(String profileName) { return hasCHProfile; } + private boolean hasCoreProfile(String profileName) { + boolean hasCoreProfile = false; + for (CHProfile chProfile : getGraphhopper().getCorePreparationHandler().getCHProfiles()) { + if (profileName.equals(chProfile.getProfile())) + hasCoreProfile = true; + } + return hasCoreProfile; + } + public long getCapacity() { GraphHopperStorage graph = mGraphHopper.getGraphHopperStorage(); return graph.getCapacity(); // TODO: how to deal with + graph.getExtension().getCapacity(); @@ -612,67 +620,108 @@ public IsochroneMap buildIsochrone(IsochroneSearchParameters parameters, String[ return result; } + /** + * Compute a NxM matrix from a request using any of the three available approaches. + * For performance reasons, RPHAST is preferred over CoreMatrix, which is preferred over DijkstraMatrix, depending on request conditions. + * + * @param req The MatrixRequest object containing details which define which approach should be used. + * @return A MatrixResult object, possibly with both time and distance values for all combinations of N and M input locations + * @throws Exception + */ public MatrixResult computeMatrix(MatrixRequest req) throws Exception { - MatrixResult mtxResult; - GraphHopper gh = getGraphhopper(); String encoderName = RoutingProfileType.getEncoderName(req.getProfileType()); FlagEncoder flagEncoder = gh.getEncodingManager().getEncoder(encoderName); PMap hintsMap = new PMap(); int weightingMethod = req.getWeightingMethod() == WeightingMethod.UNKNOWN ? WeightingMethod.RECOMMENDED : req.getWeightingMethod(); setWeighting(hintsMap, weightingMethod, req.getProfileType(), false); - String weightingName = hintsMap.getString("weighting", ""); - String profileName = makeProfileName(encoderName, weightingName); + String profileName = makeProfileName(encoderName, hintsMap.getString("weighting", "")); //TODO probably remove MatrixAlgorithmFactory alltogether as the checks for algorithm choice have to be performed here again. Or combine in a single check nicely - MatrixAlgorithm alg = MatrixAlgorithmFactory.createAlgorithm(req, gh); try { - boolean hasCHProfile = hasCHProfile(profileName); - if (!req.getFlexibleMode() && gh.getCHPreparationHandler().isEnabled() && hasCHProfile) { + // RPHAST + if (!req.getFlexibleMode() && gh.getCHPreparationHandler().isEnabled() && hasCHProfile(profileName)) { return computeRPHASTMatrix(req, gh, flagEncoder, profileName); } // Core -// else if (req.getSearchParameters().getDynamicSpeeds() && ((ORSGraphHopper) (gh)).isCoreAvailable(weighting.getName())) { - //TODO how to get graph -// RoutingCHGraph graph = gh.getGraphHopperStorage().getCoreGraph(weighting); -// RouteSearchContext searchCntx = createSearchContext(req.getSearchParameters()); -// PMap additionalHints = (PMap) searchCntx.getProperties(); -// EdgeFilter edgeFilter = this.mGraphHopper.getEdgeFilterFactory().createEdgeFilter(additionalHints, flagEncoder, this.mGraphHopper.getGraphHopperStorage()); -// -// MatrixSearchContextBuilder builder = new MatrixSearchContextBuilder(gh.getLocationIndex(), edgeFilter, req.getResolveLocations()); -// MatrixSearchContext mtxSearchCntx = builder.create(graph, req.getSources(), req.getDestinations(), MatrixServiceSettings.getMaximumSearchRadius()); -// -// weighting = createTurnWeighting(graph, weighting, TraversalMode.EDGE_BASED, MatrixServiceSettings.getUTurnCost()); -// if (weighting instanceof TurnWeighting) -// ((TurnWeighting) weighting).setInORS(true); -// ((CoreMatrixAlgorithm) alg).init(req, gh, mtxSearchCntx.getGraph(), flagEncoder, weighting, edgeFilter); -// mtxResult = alg.compute(mtxSearchCntx.getSources(), mtxSearchCntx.getDestinations(), req.getMetrics()); -// return mtxResult; -// return null; -// } - // ALT + //TODO check whether hasCoreProfile is equivalent to isCoreAvailable + else if (req.getSearchParameters().getDynamicSpeeds() && hasCoreProfile(profileName)) { //&& ((ORSGraphHopper) (gh)).isCoreAvailable(weightingName)) { + return computeCoreMatrix(); + } + // Dijkstra else { -// Graph graph = gh.getGraphHopperStorage().getBaseGraph(); -// MatrixSearchContextBuilder builder = new MatrixSearchContextBuilder(gh.getLocationIndex(), AccessFilter.allEdges(flagEncoder.getAccessEnc()), req.getResolveLocations()); -// MatrixSearchContext mtxSearchCntx = builder.create(graph, req.getSources(), req.getDestinations(), MatrixServiceSettings.getMaximumSearchRadius()); -// alg.init(req, gh, mtxSearchCntx.getGraph(), flagEncoder, weighting); -// mtxResult = alg.compute(mtxSearchCntx.getSources(), mtxSearchCntx.getDestinations(), req.getMetrics()); -// return mtxResult; - return null; + return computeDijkstraMatrix(req, gh, flagEncoder, hintsMap, profileName); } } catch (Exception ex) { throw new InternalServerException(MatrixErrorCodes.UNKNOWN, "Unable to compute a distance/duration matrix."); } } + /** + * Compute a matrix based on a contraction hierarchies graph using the RPHAST algorithm. This is fast, but inflexible. + * + * @param req + * @param gh + * @param flagEncoder + * @param profileName + * @return + * @throws Exception + */ private MatrixResult computeRPHASTMatrix(MatrixRequest req, GraphHopper gh, FlagEncoder flagEncoder, String profileName) throws Exception { - MatrixResult mtxResult; RoutingCHGraph routingCHGraph = gh.getGraphHopperStorage().getRoutingCHGraph(profileName); MatrixSearchContextBuilder builder = new MatrixSearchContextBuilder(gh.getLocationIndex(), AccessFilter.allEdges(flagEncoder.getAccessEnc()), req.getResolveLocations()); MatrixSearchContext mtxSearchCntx = builder.create(routingCHGraph.getBaseGraph(), routingCHGraph, req.getSources(), req.getDestinations(), MatrixServiceSettings.getMaximumSearchRadius()); + RPHASTMatrixAlgorithm algorithm = new RPHASTMatrixAlgorithm(); algorithm.init(req, gh, mtxSearchCntx.getRoutingCHGraph(), flagEncoder, routingCHGraph.getWeighting()); - mtxResult = algorithm.compute(mtxSearchCntx.getSources(), mtxSearchCntx.getDestinations(), req.getMetrics()); + MatrixResult mtxResult = algorithm.compute(mtxSearchCntx.getSources(), mtxSearchCntx.getDestinations(), req.getMetrics()); + return mtxResult; + } + + /** + * Compute a matrix based on a core contracted graph, which is slower than RPHAST, but offers all the flexibility of the core + * + * @return + */ + private MatrixResult computeCoreMatrix() { +// Weighting weighting = new ORSWeightingFactory().createWeighting(hintsMap, flagEncoder, gh.getGraphHopperStorage()); +// RoutingCHGraph graph = this.mGraphHopper.getGraphHopperStorage().getCoreGraph(weighting); +// RouteSearchContext searchCntx = createSearchContext(req.getSearchParameters()); +// PMap additionalHints = (PMap) searchCntx.getProperties(); +// EdgeFilter edgeFilter = this.mGraphHopper.getEdgeFilterFactory().createEdgeFilter(additionalHints, flagEncoder, this.mGraphHopper.getGraphHopperStorage()); +// +// MatrixSearchContextBuilder builder = new MatrixSearchContextBuilder(gh.getLocationIndex(), edgeFilter, req.getResolveLocations()); +// MatrixSearchContext mtxSearchCntx = builder.create(graph, req.getSources(), req.getDestinations(), MatrixServiceSettings.getMaximumSearchRadius()); +// +// weighting = createTurnWeighting(graph, weighting, TraversalMode.EDGE_BASED, MatrixServiceSettings.getUTurnCost()); +// if (weighting instanceof TurnWeighting) +// ((TurnWeighting) weighting).setInORS(true); +// ((CoreMatrixAlgorithm) alg).init(req, gh, mtxSearchCntx.getGraph(), flagEncoder, weighting, edgeFilter); +// mtxResult = alg.compute(mtxSearchCntx.getSources(), mtxSearchCntx.getDestinations(), req.getMetrics()); +// return mtxResult; + return null; + } + + /** + * Compute a matrix based on the normal graph. Slow, but highly flexible in terms of request parameters. + * + * @param req + * @param gh + * @param flagEncoder + * @param hintsMap + * @param profileName + * @return + * @throws Exception + */ + private MatrixResult computeDijkstraMatrix(MatrixRequest req, GraphHopper gh, FlagEncoder flagEncoder, PMap hintsMap, String profileName) throws Exception { + Graph graph = gh.getGraphHopperStorage().getBaseGraph(); + Weighting weighting = new OrsWeightingFactoryGh4(gh.getGraphHopperStorage(), gh.getEncodingManager()).createWeighting(gh.getProfile(profileName), hintsMap, false); + MatrixSearchContextBuilder builder = new MatrixSearchContextBuilder(gh.getLocationIndex(), AccessFilter.allEdges(flagEncoder.getAccessEnc()), req.getResolveLocations()); + MatrixSearchContext mtxSearchCntx = builder.create(graph, null, req.getSources(), req.getDestinations(), MatrixServiceSettings.getMaximumSearchRadius()); + + DijkstraMatrixAlgorithm algorithm = new DijkstraMatrixAlgorithm(); + algorithm.init(req, gh, mtxSearchCntx.getGraph(), flagEncoder, weighting); + MatrixResult mtxResult = algorithm.compute(mtxSearchCntx.getSources(), mtxSearchCntx.getDestinations(), req.getMetrics()); return mtxResult; } @@ -837,8 +886,7 @@ public RouteSegmentInfo[] getMatchedSegments(Coordinate[] locations, double sear return rsi; } - private RouteSegmentInfo[] getMatchedSegmentsInternal(Coordinate[] locations, - double searchRadius, EdgeFilter edgeFilter, boolean bothDirections) { + private RouteSegmentInfo[] getMatchedSegmentsInternal(Coordinate[] locations, double searchRadius, EdgeFilter edgeFilter, boolean bothDirections) { if (mMapMatcher == null) { mMapMatcher = new HiddenMarkovMapMatcher(); mMapMatcher.setGraphHopper(mGraphHopper); From eb03bbd8c2aaa2cea4478ef555a1ec44068a4989 Mon Sep 17 00:00:00 2001 From: Hendrik Leuschner Date: Tue, 8 Mar 2022 13:17:50 +0100 Subject: [PATCH 2/4] Remove weighting from hintsmap again --- .../src/main/java/org/heigit/ors/routing/RoutingProfile.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openrouteservice/src/main/java/org/heigit/ors/routing/RoutingProfile.java b/openrouteservice/src/main/java/org/heigit/ors/routing/RoutingProfile.java index c261cc6206..97265b2608 100644 --- a/openrouteservice/src/main/java/org/heigit/ors/routing/RoutingProfile.java +++ b/openrouteservice/src/main/java/org/heigit/ors/routing/RoutingProfile.java @@ -1128,7 +1128,7 @@ private void setWeighting(PMap map, int requestWeighting, int profileType, boole } // TODO: not permitted with GH-4.0; remove this line if it works: map.putObject(KEY_WEIGHTING, weighting); - map.putObject(KEY_WEIGHTING, weighting); +// map.putObject(KEY_WEIGHTING, weighting); map.putObject(KEY_WEIGHTING_METHOD, weightingMethod); if (hasTimeDependentSpeed) From 81e1f2211d58905e5135f52200f29fb0d82983f9 Mon Sep 17 00:00:00 2001 From: Hendrik Leuschner Date: Thu, 10 Mar 2022 14:16:33 +0100 Subject: [PATCH 3/4] Treat weighting and weightingmethod separately --- .../heigit/ors/routing/RoutingProfile.java | 47 ++++++++++++++----- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/openrouteservice/src/main/java/org/heigit/ors/routing/RoutingProfile.java b/openrouteservice/src/main/java/org/heigit/ors/routing/RoutingProfile.java index 97265b2608..a884c5423d 100644 --- a/openrouteservice/src/main/java/org/heigit/ors/routing/RoutingProfile.java +++ b/openrouteservice/src/main/java/org/heigit/ors/routing/RoutingProfile.java @@ -634,6 +634,7 @@ public MatrixResult computeMatrix(MatrixRequest req) throws Exception { FlagEncoder flagEncoder = gh.getEncodingManager().getEncoder(encoderName); PMap hintsMap = new PMap(); int weightingMethod = req.getWeightingMethod() == WeightingMethod.UNKNOWN ? WeightingMethod.RECOMMENDED : req.getWeightingMethod(); + setWeightingMethod(hintsMap, weightingMethod, req.getProfileType(), false); setWeighting(hintsMap, weightingMethod, req.getProfileType(), false); String profileName = makeProfileName(encoderName, hintsMap.getString("weighting", "")); @@ -735,7 +736,7 @@ public CentralityResult computeCentrality(CentralityRequest req) throws Exceptio PMap hintsMap = new PMap(); int weightingMethod = WeightingMethod.FASTEST; - setWeighting(hintsMap, weightingMethod, req.getProfileType(), false); + setWeightingMethod(hintsMap, weightingMethod, req.getProfileType(), false); Weighting weighting = new ORSWeightingFactory(gh.getGraphHopperStorage(), flagEncoder).createWeighting(hintsMap, false); EdgeExplorer explorer = graph.createEdgeExplorer(AccessFilter.outEdges(flagEncoder.getAccessEnc())); @@ -938,7 +939,7 @@ public GHResponse computeRoundTripRoute(double lat0, double lon0, WayPointBearin req.getHints().putAll(props); if (supportWeightingMethod(profileType)) - setWeighting(req.getHints(), weightingMethod, profileType, false); + setWeightingMethod(req.getHints(), weightingMethod, profileType, false); else throw new IllegalArgumentException("Unsupported weighting " + weightingMethod + " for profile + " + profileType); @@ -1009,7 +1010,7 @@ else if (bearings[1] == null) req.getHints().putAll(props); if (supportWeightingMethod(profileType)) { - setWeighting(req.getHints(), weightingMethod, profileType, hasTimeDependentSpeed(searchParams, searchCntx)); + setWeightingMethod(req.getHints(), weightingMethod, profileType, hasTimeDependentSpeed(searchParams, searchCntx)); if (requiresTimeDependentWeighting(searchParams, searchCntx)) flexibleMode = KEY_FLEX_PREPROCESSED; flexibleMode = getFlexibilityMode(flexibleMode, searchParams, profileType); @@ -1099,9 +1100,38 @@ private int getFlexibilityMode(int flexibleMode, RouteSearchParameters searchPar return flexibleMode; } + /** + * Set the weightingMethod for the request based on input weighting. + * + * @param map Hints map for setting up the request + * @param requestWeighting Originally requested weighting + * @param profileType Necessary for HGV + */ + private void setWeightingMethod(PMap map, int requestWeighting, int profileType, boolean hasTimeDependentSpeed) { + //Defaults + String weightingMethod = VAL_RECOMMENDED; + + if (requestWeighting == WeightingMethod.SHORTEST) + weightingMethod = VAL_SHORTEST; + + //For a requested recommended weighting, use recommended for bike, walking and hgv. Use fastest for car. + if (requestWeighting == WeightingMethod.RECOMMENDED || requestWeighting == WeightingMethod.FASTEST) { + if (profileType == RoutingProfileType.DRIVING_CAR) { + weightingMethod = VAL_FASTEST; + } + if (RoutingProfileType.isHeavyVehicle(profileType) || RoutingProfileType.isCycling(profileType) || RoutingProfileType.isWalking(profileType)) { + weightingMethod = VAL_RECOMMENDED; + } + } + + map.putObject(KEY_WEIGHTING_METHOD, weightingMethod); + + if (hasTimeDependentSpeed) + map.putObject(ORSParameters.Weighting.TIME_DEPENDENT_SPEED, true); + } + /** * Set the weighting for the request based on input weighting. - * Also set the weighting_method. * * @param map Hints map for setting up the request * @param requestWeighting Originally requested weighting @@ -1110,26 +1140,21 @@ private int getFlexibilityMode(int flexibleMode, RouteSearchParameters searchPar private void setWeighting(PMap map, int requestWeighting, int profileType, boolean hasTimeDependentSpeed) { //Defaults String weighting = VAL_RECOMMENDED; - String weightingMethod = VAL_RECOMMENDED; if (requestWeighting == WeightingMethod.SHORTEST) - weighting = weightingMethod = VAL_SHORTEST; + weighting = VAL_SHORTEST; //For a requested recommended weighting, use recommended for bike, walking and hgv. Use fastest for car. if (requestWeighting == WeightingMethod.RECOMMENDED || requestWeighting == WeightingMethod.FASTEST) { if (profileType == RoutingProfileType.DRIVING_CAR) { weighting = VAL_FASTEST; - weightingMethod = VAL_FASTEST; } if (RoutingProfileType.isHeavyVehicle(profileType) || RoutingProfileType.isCycling(profileType) || RoutingProfileType.isWalking(profileType)) { weighting = VAL_RECOMMENDED; - weightingMethod = VAL_RECOMMENDED; } } - // TODO: not permitted with GH-4.0; remove this line if it works: map.putObject(KEY_WEIGHTING, weighting); -// map.putObject(KEY_WEIGHTING, weighting); - map.putObject(KEY_WEIGHTING_METHOD, weightingMethod); + map.putObject(KEY_WEIGHTING, weighting); if (hasTimeDependentSpeed) map.putObject(ORSParameters.Weighting.TIME_DEPENDENT_SPEED, true); From fee5669c66520888ea0400489f2b230ae8065335 Mon Sep 17 00:00:00 2001 From: Hendrik Leuschner Date: Thu, 10 Mar 2022 15:13:58 +0100 Subject: [PATCH 4/4] Format --- .../dijkstra/DijkstraMatrixAlgorithm.java | 149 +++++++++--------- 1 file changed, 72 insertions(+), 77 deletions(-) diff --git a/openrouteservice/src/main/java/org/heigit/ors/matrix/algorithms/dijkstra/DijkstraMatrixAlgorithm.java b/openrouteservice/src/main/java/org/heigit/ors/matrix/algorithms/dijkstra/DijkstraMatrixAlgorithm.java index ad5d1907bd..b65725a91d 100644 --- a/openrouteservice/src/main/java/org/heigit/ors/matrix/algorithms/dijkstra/DijkstraMatrixAlgorithm.java +++ b/openrouteservice/src/main/java/org/heigit/ors/matrix/algorithms/dijkstra/DijkstraMatrixAlgorithm.java @@ -1,96 +1,91 @@ /* 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 + * 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. + * 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 . + * You should have received a copy of the GNU Lesser General Public License along with this library; + * if not, see . */ package org.heigit.ors.matrix.algorithms.dijkstra; import com.graphhopper.GraphHopper; +import com.graphhopper.routing.SPTEntry; import com.graphhopper.routing.util.FlagEncoder; import com.graphhopper.routing.util.TraversalMode; import com.graphhopper.routing.weighting.Weighting; import com.graphhopper.storage.Graph; -import com.graphhopper.routing.SPTEntry; - -import org.heigit.ors.matrix.MatrixMetricsType; -import org.heigit.ors.matrix.MatrixRequest; -import org.heigit.ors.matrix.MatrixResult; -import org.heigit.ors.matrix.MatrixLocations; -import org.heigit.ors.matrix.PathMetricsExtractor; +import org.heigit.ors.config.MatrixServiceSettings; +import org.heigit.ors.matrix.*; import org.heigit.ors.matrix.algorithms.AbstractMatrixAlgorithm; import org.heigit.ors.routing.algorithms.DijkstraOneToManyAlgorithm; -import org.heigit.ors.config.MatrixServiceSettings; public class DijkstraMatrixAlgorithm extends AbstractMatrixAlgorithm { - private PathMetricsExtractor pathMetricsExtractor; - - @Override - public void init(MatrixRequest req, GraphHopper gh, Graph graph, FlagEncoder encoder, Weighting weighting) { - super.init(req, gh, graph, encoder, weighting); - - pathMetricsExtractor = new PathMetricsExtractor(req.getMetrics(), this.graph, this.encoder, this.weighting, req.getUnits()); - } - - @Override - public MatrixResult compute(MatrixLocations srcData, MatrixLocations dstData, int metrics) throws Exception { - MatrixResult mtxResult = new MatrixResult(srcData.getLocations(), dstData.getLocations()); - - float[] times = null; - float[] distances = null; - float[] weights = null; - - int tableSize = srcData.size() * dstData.size(); - if (MatrixMetricsType.isSet(metrics, MatrixMetricsType.DURATION)) - times = new float[tableSize]; - if (MatrixMetricsType.isSet(metrics, MatrixMetricsType.DISTANCE)) - distances = new float[tableSize]; - if (MatrixMetricsType.isSet(metrics, MatrixMetricsType.WEIGHT)) - weights = new float[tableSize]; - - if (!srcData.hasValidNodes() || !dstData.hasValidNodes()) { - for (int srcIndex = 0; srcIndex < srcData.size(); srcIndex++) - pathMetricsExtractor.setEmptyValues(srcIndex, dstData, times, distances, weights); - } else { - DijkstraOneToManyAlgorithm algorithm = new DijkstraOneToManyAlgorithm(graph, weighting, TraversalMode.NODE_BASED); - algorithm.prepare(srcData.getNodeIds(), dstData.getNodeIds()); - algorithm.setMaxVisitedNodes(MatrixServiceSettings.getMaximumVisitedNodes()); - - int sourceId = -1; - - for (int srcIndex = 0; srcIndex < srcData.size(); srcIndex++) { - sourceId = srcData.getNodeId(srcIndex); - - if (sourceId == -1) { - pathMetricsExtractor.setEmptyValues(srcIndex, dstData, times, distances, weights); - } else { - algorithm.reset(); - SPTEntry[] targets = algorithm.calcPaths(sourceId, dstData.getNodeIds()); - - if (algorithm.getFoundTargets() != algorithm.getTargetsCount()) - throw new Exception("Search exceeds the limit of visited nodes."); - - if (targets != null) { - pathMetricsExtractor.calcValues(srcIndex, targets, dstData, times, distances, weights); - } - } - } - } - - if (MatrixMetricsType.isSet(metrics, MatrixMetricsType.DURATION)) - mtxResult.setTable(MatrixMetricsType.DURATION, times); - if (MatrixMetricsType.isSet(metrics, MatrixMetricsType.DISTANCE)) - mtxResult.setTable(MatrixMetricsType.DISTANCE, distances); - if (MatrixMetricsType.isSet(metrics, MatrixMetricsType.WEIGHT)) - mtxResult.setTable(MatrixMetricsType.WEIGHT, weights); - - return mtxResult; - } + private PathMetricsExtractor pathMetricsExtractor; + + @Override + public void init(MatrixRequest req, GraphHopper gh, Graph graph, FlagEncoder encoder, Weighting weighting) { + super.init(req, gh, graph, encoder, weighting); + + pathMetricsExtractor = new PathMetricsExtractor(req.getMetrics(), this.graph, this.encoder, this.weighting, req.getUnits()); + } + + @Override + public MatrixResult compute(MatrixLocations srcData, MatrixLocations dstData, int metrics) throws Exception { + MatrixResult mtxResult = new MatrixResult(srcData.getLocations(), dstData.getLocations()); + + float[] times = null; + float[] distances = null; + float[] weights = null; + + int tableSize = srcData.size() * dstData.size(); + if (MatrixMetricsType.isSet(metrics, MatrixMetricsType.DURATION)) + times = new float[tableSize]; + if (MatrixMetricsType.isSet(metrics, MatrixMetricsType.DISTANCE)) + distances = new float[tableSize]; + if (MatrixMetricsType.isSet(metrics, MatrixMetricsType.WEIGHT)) + weights = new float[tableSize]; + + if (!srcData.hasValidNodes() || !dstData.hasValidNodes()) { + for (int srcIndex = 0; srcIndex < srcData.size(); srcIndex++) + pathMetricsExtractor.setEmptyValues(srcIndex, dstData, times, distances, weights); + } else { + DijkstraOneToManyAlgorithm algorithm = new DijkstraOneToManyAlgorithm(graph, weighting, TraversalMode.NODE_BASED); + algorithm.prepare(srcData.getNodeIds(), dstData.getNodeIds()); + algorithm.setMaxVisitedNodes(MatrixServiceSettings.getMaximumVisitedNodes()); + + int sourceId = -1; + + for (int srcIndex = 0; srcIndex < srcData.size(); srcIndex++) { + sourceId = srcData.getNodeId(srcIndex); + + if (sourceId == -1) { + pathMetricsExtractor.setEmptyValues(srcIndex, dstData, times, distances, weights); + } else { + algorithm.reset(); + SPTEntry[] targets = algorithm.calcPaths(sourceId, dstData.getNodeIds()); + + if (algorithm.getFoundTargets() != algorithm.getTargetsCount()) + throw new Exception("Search exceeds the limit of visited nodes."); + + if (targets != null) { + pathMetricsExtractor.calcValues(srcIndex, targets, dstData, times, distances, weights); + } + } + } + } + + if (MatrixMetricsType.isSet(metrics, MatrixMetricsType.DURATION)) + mtxResult.setTable(MatrixMetricsType.DURATION, times); + if (MatrixMetricsType.isSet(metrics, MatrixMetricsType.DISTANCE)) + mtxResult.setTable(MatrixMetricsType.DISTANCE, distances); + if (MatrixMetricsType.isSet(metrics, MatrixMetricsType.WEIGHT)) + mtxResult.setTable(MatrixMetricsType.WEIGHT, weights); + + return mtxResult; + } }