MatrixService.java
package org.heigit.ors.api.services;
import org.heigit.ors.api.EndpointsProperties;
import org.heigit.ors.api.requests.matrix.MatrixRequest;
import org.heigit.ors.api.requests.matrix.MatrixRequestEnums;
import org.heigit.ors.api.requests.routing.RouteRequest;
import org.heigit.ors.exceptions.ParameterValueException;
import org.heigit.ors.exceptions.ServerLimitExceededException;
import org.heigit.ors.exceptions.StatusCodeException;
import org.heigit.ors.matrix.MatrixErrorCodes;
import org.heigit.ors.matrix.MatrixMetricsType;
import org.heigit.ors.matrix.MatrixResult;
import org.heigit.ors.matrix.MatrixSearchParameters;
import org.heigit.ors.api.APIEnums;
import org.heigit.ors.routing.RoutingErrorCodes;
import org.heigit.ors.routing.RoutingProfileManager;
import org.heigit.ors.routing.RoutingProfileType;
import org.locationtech.jts.geom.Coordinate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import static org.heigit.ors.api.requests.matrix.MatrixRequest.isFlexibleMode;
@Service
public class MatrixService extends ApiService {
@Autowired
public MatrixService(EndpointsProperties endpointsProperties) {
this.endpointsProperties = endpointsProperties;
}
public MatrixResult generateMatrixFromRequest(MatrixRequest matrixRequest) throws StatusCodeException {
org.heigit.ors.matrix.MatrixRequest coreRequest = this.convertMatrixRequest(matrixRequest);
try {
return RoutingProfileManager.getInstance().computeMatrix(coreRequest);
} catch (StatusCodeException e) {
throw e;
} catch (Exception e) {
throw new StatusCodeException(MatrixErrorCodes.UNKNOWN);
}
}
public org.heigit.ors.matrix.MatrixRequest convertMatrixRequest(MatrixRequest matrixRequest) throws StatusCodeException {
org.heigit.ors.matrix.MatrixRequest coreRequest = new org.heigit.ors.matrix.MatrixRequest(
endpointsProperties.getMatrix().getMaximumSearchRadius(),
endpointsProperties.getMatrix().getMaximumVisitedNodes(),
endpointsProperties.getMatrix().getUTurnCost());
int numberOfSources = matrixRequest.getSources() == null ? matrixRequest.getLocations().size() : matrixRequest.getSources().length;
int numberODestinations = matrixRequest.getDestinations() == null ? matrixRequest.getLocations().size() : matrixRequest.getDestinations().length;
Coordinate[] locations = convertLocations(matrixRequest.getLocations(), numberOfSources * numberODestinations, endpointsProperties);
coreRequest.setProfileType(convertToMatrixProfileType(matrixRequest.getProfile()));
if (matrixRequest.hasMetrics())
coreRequest.setMetrics(convertMetrics(matrixRequest.getMetrics()));
if (matrixRequest.hasDestinations())
coreRequest.setDestinations(convertDestinations(matrixRequest.getDestinations(), locations));
else {
coreRequest.setDestinations(convertDestinations(new String[]{"all"}, locations));
}
if (matrixRequest.hasSources())
coreRequest.setSources(convertSources(matrixRequest.getSources(), locations));
else {
coreRequest.setSources(convertSources(new String[]{"all"}, locations));
}
if (matrixRequest.hasId())
coreRequest.setId(matrixRequest.getId());
if (matrixRequest.hasOptimized())
coreRequest.setFlexibleMode(!matrixRequest.getOptimized());
if (matrixRequest.hasResolveLocations())
coreRequest.setResolveLocations(matrixRequest.getResolveLocations());
if (matrixRequest.hasUnits())
coreRequest.setUnits(convertUnits(matrixRequest.getUnits()));
MatrixSearchParameters params = new MatrixSearchParameters();
if (matrixRequest.hasMatrixOptions())
coreRequest.setFlexibleMode(processMatrixRequestOptions(matrixRequest, params));
coreRequest.setSearchParameters(params);
return coreRequest;
}
private boolean processMatrixRequestOptions(MatrixRequest matrixRequest, MatrixSearchParameters params) throws StatusCodeException {
try {
int profileType = convertRouteProfileType(matrixRequest.getProfile());
params.setProfileType(profileType);
} catch (Exception e) {
throw new ParameterValueException(RoutingErrorCodes.INVALID_PARAMETER_VALUE, RouteRequest.PARAM_PROFILE);
}
processRequestOptions(matrixRequest.getMatrixOptions(), params);
if (matrixRequest.getMatrixOptions().hasDynamicSpeeds()) {
params.setDynamicSpeeds(matrixRequest.getMatrixOptions().getDynamicSpeeds());
}
return isFlexibleMode(matrixRequest.getMatrixOptions());
}
public int convertMetrics(MatrixRequestEnums.Metrics[] metrics) throws ParameterValueException {
List<String> metricsAsStrings = new ArrayList<>();
for (MatrixRequestEnums.Metrics metric : metrics) {
metricsAsStrings.add(metric.toString());
}
String concatMetrics = String.join("|", metricsAsStrings);
int combined = MatrixMetricsType.getFromString(concatMetrics);
if (combined == MatrixMetricsType.UNKNOWN)
throw new ParameterValueException(MatrixErrorCodes.INVALID_PARAMETER_VALUE, MatrixRequest.PARAM_METRICS);
return combined;
}
protected Coordinate[] convertLocations(List<List<Double>> locations, int numberOfRoutes, EndpointsProperties endpointsProperties) throws ParameterValueException, ServerLimitExceededException {
if (locations == null || locations.size() < 2)
throw new ParameterValueException(MatrixErrorCodes.INVALID_PARAMETER_VALUE, MatrixRequest.PARAM_LOCATIONS);
int maximumNumberOfRoutes = endpointsProperties.getMatrix().getMaximumRoutes(false);
if (numberOfRoutes > maximumNumberOfRoutes)
throw new ServerLimitExceededException(MatrixErrorCodes.PARAMETER_VALUE_EXCEEDS_MAXIMUM, "Only a total of " + maximumNumberOfRoutes + " routes are allowed.");
ArrayList<Coordinate> locationCoordinates = new ArrayList<>();
for (List<Double> coordinate : locations) {
locationCoordinates.add(convertSingleLocationCoordinate(coordinate));
}
try {
return locationCoordinates.toArray(new Coordinate[locations.size()]);
} catch (NumberFormatException | ArrayStoreException | NullPointerException ex) {
throw new ParameterValueException(MatrixErrorCodes.INVALID_PARAMETER_VALUE, MatrixRequest.PARAM_LOCATIONS);
}
}
protected Coordinate convertSingleLocationCoordinate(List<Double> coordinate) throws ParameterValueException {
if (coordinate.size() != 2)
throw new ParameterValueException(MatrixErrorCodes.INVALID_PARAMETER_VALUE, MatrixRequest.PARAM_LOCATIONS);
return new Coordinate(coordinate.get(0), coordinate.get(1));
}
protected Coordinate[] convertSources(String[] sourcesIndex, Coordinate[] locations) throws ParameterValueException {
int length = sourcesIndex.length;
if (length == 0) return locations;
if (length == 1 && "all".equalsIgnoreCase(sourcesIndex[0])) return locations;
try {
ArrayList<Coordinate> indexCoordinateArray = convertIndexToLocations(sourcesIndex, locations);
return indexCoordinateArray.toArray(new Coordinate[0]);
} catch (Exception ex) {
throw new ParameterValueException(MatrixErrorCodes.INVALID_PARAMETER_VALUE, MatrixRequest.PARAM_SOURCES);
}
}
protected Coordinate[] convertDestinations(String[] destinationsIndex, Coordinate[] locations) throws ParameterValueException {
int length = destinationsIndex.length;
if (length == 0) return locations;
if (length == 1 && "all".equalsIgnoreCase(destinationsIndex[0])) return locations;
try {
ArrayList<Coordinate> indexCoordinateArray = convertIndexToLocations(destinationsIndex, locations);
return indexCoordinateArray.toArray(new Coordinate[0]);
} catch (Exception ex) {
throw new ParameterValueException(MatrixErrorCodes.INVALID_PARAMETER_VALUE, MatrixRequest.PARAM_DESTINATIONS);
}
}
protected ArrayList<Coordinate> convertIndexToLocations(String[] index, Coordinate[] locations) {
ArrayList<Coordinate> indexCoordinates = new ArrayList<>();
for (String indexString : index) {
int indexInteger = Integer.parseInt(indexString);
indexCoordinates.add(locations[indexInteger]);
}
return indexCoordinates;
}
protected int convertToMatrixProfileType(APIEnums.Profile profile) throws ParameterValueException {
try {
int profileFromString = RoutingProfileType.getFromString(profile.toString());
if (profileFromString == 0) {
throw new ParameterValueException(MatrixErrorCodes.INVALID_PARAMETER_VALUE, MatrixRequest.PARAM_PROFILE);
}
return profileFromString;
} catch (Exception e) {
throw new ParameterValueException(MatrixErrorCodes.INVALID_PARAMETER_VALUE, MatrixRequest.PARAM_PROFILE);
}
}
}