Skip to content

Commit

Permalink
Feat: custom model requests (#1950)
Browse files Browse the repository at this point in the history
  • Loading branch information
takb authored Jan 20, 2025
2 parents c0c25ac + 603b94e commit fa65057
Show file tree
Hide file tree
Showing 29 changed files with 788 additions and 218 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ RELEASING:
### Added
- take into account tunnel categories B, C, D, and E when restricting roads for the transport of dangerous goods via the `hazmat` flag in vehicle parameters ([#1879](https://github.com/GIScience/openrouteservice/pull/1879))
- Ukrainian translation ([#1883](https://github.com/GIScience/openrouteservice/pull/1883))
- add new functionality to download new routing graphs from a remote
repository ([#1889](https://github.com/GIScience/openrouteservice/pull/1889))
- add new functionality to download new routing graphs from a remote repository ([#1889](https://github.com/GIScience/openrouteservice/pull/1889))
- add support for custom model for directions requests ([#1950](https://github.com/GIScience/openrouteservice/pull/1950))
### Changed
- update docs dependency: VitePress ([#1872](https://github.com/GIScience/openrouteservice/pull/1872))
- adjust documentation for export endpoint ([#1872](https://github.com/GIScience/openrouteservice/pull/1872))
Expand Down
1 change: 1 addition & 0 deletions docs/api-reference/error-codes.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Endpoints.
| 2015 | Entry not reached. |
| 2016 | No route between entry and exit found. |
| 2017 | Maximum number of nodes exceeded. |
| 2018 | Unsupported request option. |
| 2099 | Unknown internal error. |

### Isochrones API
Expand Down
1 change: 1 addition & 0 deletions docs/run-instance/configuration/engine/profiles/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Properties beneath `ors.engine.profiles.<PROFILE-NAME>.build.encoder_options`:
| problematic_speed_factor | number | wheelchair | Travel speeds on edges classified as problematic for wheelchair users are multiplied by this factor, use to set slow traveling speeds on such ways | `0.7` |
| turn_costs | boolean | car, hgv, bike-* | Should turn restrictions be respected | `true` |
| use_acceleration | boolean | car, hgv | Models how a vehicle would accelerate on the road segment to the maximum allowed speed. In practice it reduces speed on shorter road segments such as ones between nearby intersections in a city | `true` |
| enable_custom_models | boolean | * | Enables whether the profile is prepared to support custom models. | `false` |

## `preparation`

Expand Down
25 changes: 13 additions & 12 deletions docs/run-instance/configuration/engine/profiles/service.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,19 @@ that
need to be set specifically for each profile. More parameters relevant at query time can be found in the [
`ors.endpoints`](/api-reference/endpoints/index.md) section.

| key | type | description | default value |
|-------------------------------------|---------|-----------------------------------------------------------------------------------------------------------|---------------|
| maximum_distance | number | The maximum allowed total distance of a route | `100000` |
| maximum_distance_dynamic_weights | number | The maximum allowed distance between two way points when dynamic weights are used | `100000` |
| maximum_distance_avoid_areas | number | The maximum allowed distance between two way points when areas to be avoided are provided | `100000` |
| maximum_distance_alternative_routes | number | The maximum allowed total distance of a route for the alternative routes algorithm | `100000` |
| maximum_distance_round_trip_routes | number | The maximum allowed total distance of a route for the round trip algorithm | `100000` |
| maximum_way_points | number | The maximum number of way points in a request | `50` |
| maximum_snapping_radius | number | Maximum distance around a given coordinate to find connectable edges | `400` |
| maximum_visited_nodes | number | Only for `public-transport` profile: maximum allowed number of visited nodes in shortest path computation | `1000000` |
| force_turn_costs | boolean | Should turn restrictions be obeyed | `false` |
| execution | object | [Execution settings](#execution) relevant when querying services | |
| key | type | description | default value |
|-------------------------------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|
| maximum_distance | number | The maximum allowed total distance of a route | `100000` |
| maximum_distance_dynamic_weights | number | The maximum allowed distance between two way points when dynamic weights are used | `100000` |
| maximum_distance_avoid_areas | number | The maximum allowed distance between two way points when areas to be avoided are provided | `100000` |
| maximum_distance_alternative_routes | number | The maximum allowed total distance of a route for the alternative routes algorithm | `100000` |
| maximum_distance_round_trip_routes | number | The maximum allowed total distance of a route for the round trip algorithm | `100000` |
| maximum_way_points | number | The maximum number of way points in a request | `50` |
| maximum_snapping_radius | number | Maximum distance around a given coordinate to find connectable edges | `400` |
| maximum_visited_nodes | number | Only for `public-transport` profile: maximum allowed number of visited nodes in shortest path computation | `1000000` |
| force_turn_costs | boolean | Should turn restrictions be obeyed | `false` |
| allow_custom_models | boolean | Allows custom model requests on this profile. Requires that `encoder_options.enable_custom_models` is set to true in the [build](build.md#encoder_options) section of this profile. | `false` |
| execution | object | [Execution settings](#execution) relevant when querying services | |

## `execution`

Expand Down
3 changes: 2 additions & 1 deletion ors-api/src/main/java/org/heigit/ors/api/APIEnums.java
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,8 @@ public String toString() {
public enum RoutePreference {
FASTEST("fastest"),
SHORTEST("shortest"),
RECOMMENDED("recommended");
RECOMMENDED("recommended"),
CUSTOM("custom");

private final String value;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

package org.heigit.ors.api.controllers;

import com.graphhopper.routing.ev.EncodedValue;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import org.heigit.ors.api.config.EndpointsProperties;
Expand All @@ -24,6 +25,7 @@
import org.heigit.ors.routing.RoutingProfile;
import org.heigit.ors.routing.RoutingProfileManager;
import org.heigit.ors.routing.RoutingProfileManagerStatus;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
Expand Down Expand Up @@ -101,6 +103,11 @@ public ResponseEntity getStatus(HttpServletRequest request) throws Exception {
if (profile.getBuild().getExtStorages() != null && !profile.getBuild().getExtStorages().isEmpty())
jProfileProps.put("storages", profile.getBuild().getExtStorages());

var profile_evs = rp.getGraphhopper().getEncodingManager().getEncodedValues();
if (profile_evs != null && !profile_evs.isEmpty()) {
JSONArray jEVs = new JSONArray(profile_evs.stream().map(EncodedValue::getName).toArray());
jProfileProps.put("encoded_values",jEVs);
}
jProfiles.put(profile.getProfileName(), jProfileProps);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@
import io.swagger.v3.oas.annotations.extensions.Extension;
import io.swagger.v3.oas.annotations.extensions.ExtensionProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import org.heigit.ors.api.APIEnums;
import org.heigit.ors.api.requests.common.APIRequest;
import org.heigit.ors.exceptions.ParameterValueException;
import org.heigit.ors.api.APIEnums;
import org.heigit.ors.routing.RouteRequestParameterNames;
import org.heigit.ors.routing.RoutingErrorCodes;
import org.heigit.ors.routing.RoutingProfileType;
Expand Down Expand Up @@ -331,6 +332,28 @@ Specifies a list of pairs (bearings and deviations) to filter the segments of th
@JsonIgnore
private boolean hasIgnoreTransfers = false;

@Getter
@Schema(name = PARAM_CUSTOM_MODEL, description = "Specifies custom model for weighting.", example = """
{\
"speed": [\
{\
"if": true,\
"limit_to": 100\
}\
],\
"priority": [\
{\
"if": "road_class == MOTORWAY",\
"multiply_by": 0\
}\
],\
"distance_influence": 100\
}""")
@JsonProperty(PARAM_CUSTOM_MODEL)
private RouteRequestCustomModel customModel;
@JsonIgnore
private boolean hasCustomModel = false;

@JsonCreator
public RouteRequest(@JsonProperty(value = PARAM_COORDINATES, required = true) List<List<Double>> coordinates) {
this.coordinates = coordinates;
Expand Down Expand Up @@ -754,4 +777,12 @@ public boolean isPtRequest() {
return convertRouteProfileType(profile) == RoutingProfileType.PUBLIC_TRANSPORT;
}

public void setCustomModel(RouteRequestCustomModel customModel) {
this.customModel = customModel;
this.hasCustomModel = true;
}

public boolean hasCustomModel() {
return hasCustomModel;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.heigit.ors.api.requests.routing;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.graphhopper.jackson.StatementDeserializer;
import com.graphhopper.json.Statement;
import com.graphhopper.util.CustomModel;
import com.graphhopper.util.JsonFeature;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class RouteRequestCustomModel {
@JsonProperty("distance_influence")
private double distanceInfluence;

@JsonProperty("heading_penalty")
private double headingPenalty = (double) 300.0F;

@JsonProperty("speed")
@JsonDeserialize(contentUsing = StatementDeserializer.class)
private List<Statement> speedStatements = new ArrayList<>();

@JsonProperty("priority")
@JsonDeserialize(contentUsing = StatementDeserializer.class)
private List<Statement> priorityStatements = new ArrayList<>();

@JsonProperty("areas")
private Map<String, JsonFeature> areas = new HashMap();

public CustomModel toGHCustomModel() {
CustomModel customModel = new CustomModel();
customModel.setDistanceInfluence(this.distanceInfluence);
customModel.setHeadingPenalty(this.headingPenalty);
this.speedStatements.forEach(customModel::addToSpeed);
this.priorityStatements.forEach(customModel::addToPriority);
customModel.setAreas(this.areas);
return customModel;
}
}
Loading

0 comments on commit fa65057

Please sign in to comment.