diff --git a/CHANGELOG.md b/CHANGELOG.md index d38080df45..8e70091103 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ RELEASING: - Dockerfile now creates intermediate directories if they are not present ([#1109](https://github.com/GIScience/openrouteservice/issues/1109)) - internal properties of `IsochronesRequest` model not ignored for swagger file generation - remove non-parameter `metricsStrings` from API documentation ([#756](https://github.com/GIScience/openrouteservice/issues/756)) +- set default vehicle type for HGV profile ([#816](https://github.com/GIScience/openrouteservice/issues/816)) ## [6.7.0] - 2022-01-04 ### Added diff --git a/openrouteservice-api-tests/src/test/java/org/heigit/ors/v2/services/isochrones/fast/ResultTest.java b/openrouteservice-api-tests/src/test/java/org/heigit/ors/v2/services/isochrones/fast/ResultTest.java index dce49a1e3a..e5ffcd21a9 100644 --- a/openrouteservice-api-tests/src/test/java/org/heigit/ors/v2/services/isochrones/fast/ResultTest.java +++ b/openrouteservice-api-tests/src/test/java/org/heigit/ors/v2/services/isochrones/fast/ResultTest.java @@ -27,6 +27,7 @@ @EndPointAnnotation(name = "isochrones") @VersionAnnotation(version = "v2") public class ResultTest extends ServiceTest { + private static float REACHFACTOR_REFERENCE_VALUE = 0.0648f; public ResultTest() { @@ -116,9 +117,9 @@ public void testPolygon() { .then() .body("any { it.key == 'type' }", is(true)) .body("any { it.key == 'features' }", is(true)) - .body("features[0].geometry.coordinates[0].size()", is(88)) + .body("features[0].geometry.coordinates[0].size()", is(85)) .body("features[0].properties.center.size()", is(2)) - .body("bbox", hasItems(8.652489f, 49.40263f, 8.708881f, 49.447865f)) + .body("bbox", hasItems(8.652559f, 49.40263f, 8.708881f, 49.447865f)) .body("features[0].type", is("Feature")) .body("features[0].geometry.type", is("Polygon")) .body("features[0].properties.group_index", is(0)) @@ -187,7 +188,7 @@ public void testBoundingBox() { .when() .post(getEndPointPath() + "/{profile}/geojson") .then() - .body("bbox[0]", is(8.652489f)) + .body("bbox[0]", is(8.652559f)) .body("bbox[1]", is(49.40263f)) .body("bbox[2]", is(8.708881f)) .body("bbox[3]", is(49.447865f)) @@ -213,7 +214,7 @@ public void testReachfactorAndArea() { .body("any { it.key == 'type' }", is(true)) .body("any { it.key == 'features' }", is(true)) .body("features[0].properties.area", is(both(greaterThan(12000000f)).and(lessThan(13000000f)))) - .body("features[0].properties.reachfactor", is(0.0663f)) + .body("features[0].properties.reachfactor", is(REACHFACTOR_REFERENCE_VALUE)) .statusCode(200); } @@ -238,7 +239,7 @@ public void testReachfactorAndAreaAreaUnitsM() { .body("any { it.key == 'type' }", is(true)) .body("any { it.key == 'features' }", is(true)) .body("features[0].properties.area", is(both(greaterThan(12000000f)).and(lessThan(13000000f)))) - .body("features[0].properties.reachfactor", is(0.0663f)) + .body("features[0].properties.reachfactor", is(REACHFACTOR_REFERENCE_VALUE)) .statusCode(200); } @@ -263,7 +264,7 @@ public void testReachfactorAndAreaAreaUnitsKM() { .body("any { it.key == 'type' }", is(true)) .body("any { it.key == 'features' }", is(true)) .body("features[0].properties.area", is(both(greaterThan(12.0f)).and(lessThan(13.0f)))) - .body("features[0].properties.reachfactor", is(0.0663f)) + .body("features[0].properties.reachfactor", is(REACHFACTOR_REFERENCE_VALUE)) .statusCode(200); } @@ -314,7 +315,7 @@ public void testReachfactorAndAreaAreaUnitsMI() { .body("any { it.key == 'type' }", is(true)) .body("any { it.key == 'features' }", is(true)) .body("features[0].properties.area", is(both(greaterThan(4.7f)).and(lessThan(5.0f)))) - .body("features[0].properties.reachfactor", is(0.0663f)) + .body("features[0].properties.reachfactor", is(REACHFACTOR_REFERENCE_VALUE)) .statusCode(200); } @@ -345,7 +346,7 @@ public void testIntersections() { .body("features[1].geometry.type", is("Polygon")) .body("features[2].type", is("Feature")) .body("features[2].geometry.type", is("Polygon")) - .body("features[2].geometry.coordinates[0].size()", is(86)) + .body("features[2].geometry.coordinates[0].size()", is(80)) .body("features[2].properties.contours.size()", is(2)) .body("features[2].properties.containsKey('area')", is(true)) .body("features[0].properties.area", is(both(greaterThan(12000000f)).and(lessThan(13000000f)))) @@ -379,7 +380,7 @@ public void testSmoothingFactor() { .then() .body("any { it.key == 'type' }", is(true)) .body("any { it.key == 'features' }", is(true)) - .body("features[0].geometry.coordinates[0].size", is(75)) + .body("features[0].geometry.coordinates[0].size", is(69)) .statusCode(200); body.put("smoothing", "100"); @@ -393,7 +394,7 @@ public void testSmoothingFactor() { .then() .body("any { it.key == 'type' }", is(true)) .body("any { it.key == 'features' }", is(true)) - .body("features[0].geometry.coordinates[0].size", is(89)) + .body("features[0].geometry.coordinates[0].size", is(94)) .statusCode(200); } diff --git a/openrouteservice/src/main/java/org/heigit/ors/routing/RouteSearchParameters.java b/openrouteservice/src/main/java/org/heigit/ors/routing/RouteSearchParameters.java index 52fae856d1..d3479421b6 100644 --- a/openrouteservice/src/main/java/org/heigit/ors/routing/RouteSearchParameters.java +++ b/openrouteservice/src/main/java/org/heigit/ors/routing/RouteSearchParameters.java @@ -57,6 +57,7 @@ public class RouteSearchParameters { public static final String KEY_AVOID_POLYGONS = "avoid_polygons"; public static final String KEY_ALTERNATIVE_ROUTES_WEIGHT_FACTOR = "alternative_routes_weight_factor"; public static final String KEY_ALTERNATIVE_ROUTES_SHARE_FACTOR = "alternative_routes_share_factor"; + public static final int DEFAULT_HGV_VEHICLE_TYPE = HeavyVehicleAttributes.HGV; private int profileType; private int weightingMethod = WeightingMethod.FASTEST; private Boolean considerTurnRestrictions = false; @@ -100,6 +101,9 @@ public void setProfileType(int profileType) throws Exception { throw new Exception("Routing profile is unknown."); this.profileType = profileType; + + if (RoutingProfileType.isHeavyVehicle(profileType)) + setVehicleType(DEFAULT_HGV_VEHICLE_TYPE); } public int getWeightingMethod() { @@ -304,34 +308,34 @@ public void setOptions(String options) throws Exception { if (json.has("vehicle_type")) { String type = json.getString("vehicle_type"); - this.vehicleType = HeavyVehicleAttributes.getFromString(type); + setVehicleType(HeavyVehicleAttributes.getFromString(type)); + } - // Since 4.2, all restrictions are packed in its own element - if (jRestrictions == null) - jRestrictions = jProfileParams; + // Since 4.2, all restrictions are packed in its own element + if (jRestrictions == null) + jRestrictions = jProfileParams; - if (jRestrictions.has("length")) - vehicleParams.setLength(jRestrictions.getDouble("length")); + if (jRestrictions.has("length")) + vehicleParams.setLength(jRestrictions.getDouble("length")); - if (jRestrictions.has("width")) - vehicleParams.setWidth(jRestrictions.getDouble("width")); + if (jRestrictions.has("width")) + vehicleParams.setWidth(jRestrictions.getDouble("width")); - if (jRestrictions.has("height")) - vehicleParams.setHeight(jRestrictions.getDouble("height")); + if (jRestrictions.has("height")) + vehicleParams.setHeight(jRestrictions.getDouble("height")); - if (jRestrictions.has("weight")) - vehicleParams.setWeight(jRestrictions.getDouble("weight")); + if (jRestrictions.has("weight")) + vehicleParams.setWeight(jRestrictions.getDouble("weight")); - if (jRestrictions.has("axleload")) - vehicleParams.setAxleload(jRestrictions.getDouble("axleload")); + if (jRestrictions.has("axleload")) + vehicleParams.setAxleload(jRestrictions.getDouble("axleload")); - int loadCharacteristics = 0; - if (jRestrictions.has("hazmat") && jRestrictions.getBoolean("hazmat")) - loadCharacteristics |= VehicleLoadCharacteristicsFlags.HAZMAT; + int loadCharacteristics = 0; + if (jRestrictions.has("hazmat") && jRestrictions.getBoolean("hazmat")) + loadCharacteristics |= VehicleLoadCharacteristicsFlags.HAZMAT; - if (loadCharacteristics != 0) - vehicleParams.setLoadCharacteristics(loadCharacteristics); - } + if (loadCharacteristics != 0) + vehicleParams.setLoadCharacteristics(loadCharacteristics); profileParams = vehicleParams; } else if (profileType == RoutingProfileType.WHEELCHAIR) { @@ -572,13 +576,17 @@ public boolean isProfileTypeHeavyVehicle() { return RoutingProfileType.isHeavyVehicle(this.getProfileType()); } + public boolean hasNonDefaultVehicleType() { + return isProfileTypeHeavyVehicle() && getVehicleType() != DEFAULT_HGV_VEHICLE_TYPE; + } + public boolean requiresDynamicPreprocessedWeights() { return hasAvoidAreas() || hasAvoidFeatures() || hasAvoidBorders() || hasAvoidCountries() || getConsiderTurnRestrictions() - || isProfileTypeHeavyVehicle() && getVehicleType() > 0 + || hasNonDefaultVehicleType() || isProfileTypeDriving() && hasParameters(VehicleParameters.class) || hasMaximumSpeed(); } diff --git a/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/ORSGraphHopper.java b/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/ORSGraphHopper.java index 6a34700a98..7b4e27a3ac 100644 --- a/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/ORSGraphHopper.java +++ b/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/ORSGraphHopper.java @@ -42,7 +42,6 @@ import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; -import org.geotools.feature.SchemaException; import org.heigit.ors.api.requests.routing.RouteRequest; import org.heigit.ors.common.TravelRangeType; import org.heigit.ors.fastisochrones.Contour; @@ -62,14 +61,16 @@ import org.heigit.ors.routing.graphhopper.extensions.core.PrepareCore; 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.TrafficEdgeFilter; +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.ORSPMap; import org.heigit.ors.routing.graphhopper.extensions.util.ORSParameters; +import org.heigit.ors.routing.graphhopper.extensions.weighting.HgvAccessWeighting; import org.heigit.ors.routing.graphhopper.extensions.weighting.MaximumSpeedCalculator; import org.heigit.ors.routing.pathprocessors.BordersExtractor; import org.heigit.ors.util.CoordTools; @@ -82,6 +83,8 @@ import java.util.*; import java.util.concurrent.locks.Lock; +import static com.graphhopper.routing.ch.CHAlgoFactoryDecorator.EdgeBasedCHMode.EDGE_OR_NODE; +import static com.graphhopper.routing.ch.CHAlgoFactoryDecorator.EdgeBasedCHMode.OFF; import static com.graphhopper.routing.weighting.TurnWeighting.INFINITE_U_TURN_COSTS; import static com.graphhopper.util.Parameters.Algorithms.*; import static org.heigit.ors.routing.RouteResult.KEY_TIMEZONE_ARRIVAL; @@ -612,6 +615,44 @@ public void initLMAlgoFactoryDecorator() { ORSWeightingFactory.addTrafficSpeedCalculator(getLMFactoryDecorator().getWeightings(), getGraphHopperStorage()); } + @Override + public void initCHAlgoFactoryDecorator() { + CHAlgoFactoryDecorator chFactoryDecorator = getCHFactoryDecorator(); + EncodingManager encodingManager = getEncodingManager(); + if (!chFactoryDecorator.hasCHProfiles()) { + for (FlagEncoder encoder : encodingManager.fetchEdgeEncoders()) { + for (String chWeightingStr : chFactoryDecorator.getCHProfileStrings()) { + // ghStorage is null at this point + + // extract weighting string and u-turn-costs + String configStr = ""; + if (chWeightingStr.contains("|")) { + configStr = chWeightingStr; + chWeightingStr = chWeightingStr.split("\\|")[0]; + } + PMap config = new PMap(configStr); + int uTurnCosts = config.getInt(Parameters.Routing.U_TURN_COSTS, INFINITE_U_TURN_COSTS); + + Weighting weighting = createWeighting(new HintsMap(chWeightingStr), encoder, null); + if (encoder.toString().equals(FlagEncoderNames.HEAVYVEHICLE) && graphStorageFactory instanceof ORSGraphStorageFactory) { + ORSGraphStorageFactory orsGraphStorageFactory = (ORSGraphStorageFactory) graphStorageFactory; + HeavyVehicleAttributesGraphStorage hgvStorage = GraphStorageUtils.getGraphExtension(orsGraphStorageFactory.getGraphExtension(), HeavyVehicleAttributesGraphStorage.class); + EdgeFilter hgvEdgeFilter = new HeavyVehicleEdgeFilter(HeavyVehicleAttributes.HGV, null, hgvStorage); + weighting = new HgvAccessWeighting(weighting, hgvEdgeFilter); + } + + CHAlgoFactoryDecorator.EdgeBasedCHMode edgeBasedCHMode = chFactoryDecorator.getEdgeBasedCHMode(); + if (!(edgeBasedCHMode == EDGE_OR_NODE && encoder.supports(TurnWeighting.class))) { + chFactoryDecorator.addCHProfile(CHProfile.nodeBased(weighting)); + } + if (edgeBasedCHMode != OFF && encoder.supports(TurnWeighting.class)) { + chFactoryDecorator.addCHProfile(CHProfile.edgeBased(weighting, uTurnCosts)); + } + } + } + } + } + /** * Does the preparation and creates the location index as well as the traffic graph storage */ diff --git a/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/ORSGraphStorageFactory.java b/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/ORSGraphStorageFactory.java index 7437cd6934..57c07784dc 100644 --- a/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/ORSGraphStorageFactory.java +++ b/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/ORSGraphStorageFactory.java @@ -31,6 +31,8 @@ public class ORSGraphStorageFactory implements GraphStorageFactory { private final List graphStorageBuilders; + private GraphExtension graphExtension = null; + public ORSGraphStorageFactory(List graphStorageBuilders) { this.graphStorageBuilders = graphStorageBuilders; } @@ -65,8 +67,6 @@ public GraphHopperStorage createStorage(GHDirectory dir, GraphHopper gh) { } } - GraphExtension graphExtension = null; - if (geTurnCosts == null && graphExtensions.isEmpty()) graphExtension = new GraphExtension.NoOpExtension(); else if (geTurnCosts != null && !graphExtensions.isEmpty()) { @@ -127,4 +127,8 @@ private boolean hasGraph(GraphHopper gh) { } return false; } + + public GraphExtension getGraphExtension() { + return graphExtension; + } } diff --git a/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/edgefilters/HeavyVehicleEdgeFilter.java b/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/edgefilters/HeavyVehicleEdgeFilter.java index d3e5e17891..4b531b2629 100644 --- a/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/edgefilters/HeavyVehicleEdgeFilter.java +++ b/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/edgefilters/HeavyVehicleEdgeFilter.java @@ -67,6 +67,10 @@ public IntObjectMap getMap() private static final int MODE_ROUTE = 0; public HeavyVehicleEdgeFilter(int vehicleType, VehicleParameters vehicleParams, GraphStorage graphStorage) { + this(vehicleType, vehicleParams, GraphStorageUtils.getGraphExtension(graphStorage, HeavyVehicleAttributesGraphStorage.class)); + } + + public HeavyVehicleEdgeFilter(int vehicleType, VehicleParameters vehicleParams, HeavyVehicleAttributesGraphStorage hgvStorage) { float[] vehicleAttrs = new float[VehicleDimensionRestrictions.COUNT]; if (vehicleParams!=null) { @@ -100,7 +104,7 @@ public HeavyVehicleEdgeFilter(int vehicleType, VehicleParameters vehicleParams, this.vehicleType = vehicleType; this.buffer = new byte[2]; - this.gsHeavyVehicles = GraphStorageUtils.getGraphExtension(graphStorage, HeavyVehicleAttributesGraphStorage.class); + this.gsHeavyVehicles = hgvStorage; } public void setDestinationEdge(EdgeIteratorState edge, Graph graph, FlagEncoder encoder, TraversalMode tMode) { diff --git a/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/storages/GraphStorageUtils.java b/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/storages/GraphStorageUtils.java index d78ef318bf..bdaddfc0ae 100644 --- a/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/storages/GraphStorageUtils.java +++ b/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/storages/GraphStorageUtils.java @@ -26,20 +26,24 @@ public static T getGraphExtension(GraphStorage graphS if (graphStorage instanceof GraphHopperStorage) { GraphHopperStorage ghs = (GraphHopperStorage) graphStorage; GraphExtension ge = ghs.getExtension(); + return getGraphExtension(ge, type); + } + return null; + } - if(ge instanceof ExtendedStorageSequence) { - ExtendedStorageSequence ess = (ExtendedStorageSequence)ge; - GraphExtension[] exts = ess.getExtensions(); - for (int i = 0; i < exts.length; i++) { - if (type.isInstance(exts[i])) { - return (T)exts[i]; - } - } - } else { - if (type.isInstance(ge)) { - return (T)ge; + public static T getGraphExtension(GraphExtension ge, Class type) { + if (ge instanceof ExtendedStorageSequence) { + ExtendedStorageSequence ess = (ExtendedStorageSequence)ge; + GraphExtension[] exts = ess.getExtensions(); + for (int i = 0; i < exts.length; i++) { + if (type.isInstance(exts[i])) { + return (T)exts[i]; } } + } else { + if (type.isInstance(ge)) { + return (T)ge; + } } return null; } diff --git a/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/weighting/HgvAccessWeighting.java b/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/weighting/HgvAccessWeighting.java new file mode 100644 index 0000000000..d400acefc7 --- /dev/null +++ b/openrouteservice/src/main/java/org/heigit/ors/routing/graphhopper/extensions/weighting/HgvAccessWeighting.java @@ -0,0 +1,31 @@ +package org.heigit.ors.routing.graphhopper.extensions.weighting; + +import com.graphhopper.routing.util.EdgeFilter; +import com.graphhopper.routing.weighting.AbstractAdjustedWeighting; +import com.graphhopper.routing.weighting.Weighting; +import com.graphhopper.util.EdgeIteratorState; + +public class HgvAccessWeighting extends AbstractAdjustedWeighting { + EdgeFilter hgvAccessFilter; + + public HgvAccessWeighting(Weighting superWeighting, EdgeFilter hgvAccessFilter) { + super(superWeighting); + this.hgvAccessFilter = hgvAccessFilter; + } + + @Override + public double calcWeight(EdgeIteratorState edge, boolean reverse, int prevOrNextEdgeId, long time) { + if (!hgvAccessFilter.accept(edge)) + return Double.POSITIVE_INFINITY; + return superWeighting.calcWeight(edge, reverse, prevOrNextEdgeId, time); + } + + @Override + public String toString() { + return "hgv_access|" + this.superWeighting.toString(); + } + + public String getName() { + return this.superWeighting.getName(); + } +} diff --git a/openrouteservice/src/test/java/org/heigit/ors/routing/RouteSearchParametersTest.java b/openrouteservice/src/test/java/org/heigit/ors/routing/RouteSearchParametersTest.java index 6cd27d4f4a..4b8916da4f 100644 --- a/openrouteservice/src/test/java/org/heigit/ors/routing/RouteSearchParametersTest.java +++ b/openrouteservice/src/test/java/org/heigit/ors/routing/RouteSearchParametersTest.java @@ -249,8 +249,9 @@ public void requiresDynamicPreprocessedWeights() throws Exception { routeSearchParameters = new RouteSearchParameters(); routeSearchParameters.setProfileType(RoutingProfileType.DRIVING_HGV); - routeSearchParameters.setVehicleType(HeavyVehicleAttributes.HGV); - Assert.assertTrue("heavy vehicle", routeSearchParameters.requiresDynamicPreprocessedWeights()); + Assert.assertFalse("default vehicle type", routeSearchParameters.requiresDynamicPreprocessedWeights()); + routeSearchParameters.setVehicleType(HeavyVehicleAttributes.BUS); + Assert.assertTrue("non-default vehicle type", routeSearchParameters.requiresDynamicPreprocessedWeights()); routeSearchParameters = new RouteSearchParameters(); routeSearchParameters.setProfileType(RoutingProfileType.DRIVING_HGV);