From 5cc38b1ab3d1d8d259be7b221e93187eef1cdd2a Mon Sep 17 00:00:00 2001 From: dzmitryfomchyn Date: Thu, 31 Jul 2025 18:27:12 +0200 Subject: [PATCH 1/5] Fix changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 870243612..fda05b09b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,11 @@ Mapbox welcomes participation and contributions from everyone. ### main +### v7.5.0 - July 31, 2025 + - Updated `auto-value-gson` to version [0.0.3](https://github.com/mapbox/auto-value-gson/releases/tag/mapbox-v0.0.3) and `gson` to version 2.13.1. [#1615](https://github.com/mapbox/mapbox-java/pull/1615) + ### v7.4.0 - April 11, 2025 - Added `IntersectionLanes#access` property which provides lane access attributes, such as allowed vehicle types for designated lanes. [#1608](https://github.com/mapbox/mapbox-java/pull/1608) From 963fa94caa7378d356c060fa4352317da2c5d6f6 Mon Sep 17 00:00:00 2001 From: dzmitryfomchyn Date: Thu, 31 Jul 2025 18:27:32 +0200 Subject: [PATCH 2/5] Add new route properties --- CHANGELOG.md | 7 + .../directions/v5/models/RouteOptions.java | 182 ++++++++++++++++++ .../v5/models/StepIntersection.java | 148 ++++++++++++++ .../v5/models/DirectionsRouteTest.java | 101 ++++++++++ .../v5/models/RouteOptionsTest.java | 100 +++++++++- .../v5/models/StepIntersectionTest.java | 181 ++++++++++++++++- ...rections_v5_with_toll_costs_and_lanes.json | 31 ++- .../src/test/resources/route_options_v5.json | 9 +- 8 files changed, 750 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fda05b09b..8c8198359 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ Mapbox welcomes participation and contributions from everyone. ### main +- Added `StepIntersection#formOfWay` property which provides a list representing the "form of way" values for all roads at the step intersection. [#1611](https://github.com/mapbox/mapbox-java/pull/1611) +- Added `StepIntersection#geometries` property which provides a list representing the geometry of each road at the step intersection. [#1611](https://github.com/mapbox/mapbox-java/pull/1611) +- Added `StepIntersection#access` property which provides a list representing the access type for each road at the step intersection. [#1611](https://github.com/mapbox/mapbox-java/pull/1611) +- Added `StepIntersection#elevated` property which provides a list indicating whether each road at the step intersection is elevated. [#1611](https://github.com/mapbox/mapbox-java/pull/1611) +- Added `StepIntersection#bridge` property which provides a list indicating whether each road at the step intersection is a bridge. [#1611](https://github.com/mapbox/mapbox-java/pull/1611) + + ### v7.5.0 - July 31, 2025 - Updated `auto-value-gson` to version [0.0.3](https://github.com/mapbox/auto-value-gson/releases/tag/mapbox-v0.0.3) and `gson` to version 2.13.1. [#1615](https://github.com/mapbox/mapbox-java/pull/1615) diff --git a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java index a16746293..9afba4106 100644 --- a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java +++ b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java @@ -946,6 +946,76 @@ public List paymentMethodsList() { @Nullable public abstract Boolean suppressVoiceInstructionLocalNames(); + /** + * Defines whether to return "form of way" values for roads at each {@link StepIntersection}. + * See {@link StepIntersection#formOfWay()} for details. + * Requires {@link RouteOptions#steps()} to be set to true. + * + * @return boolean representing the `intersectionLinkFormOfWay` value + */ + @SerializedName("intersection_link_form_of_way") + @Nullable + public abstract Boolean intersectionLinkFormOfWay(); + + /** + * A comma-separated list of road classes for which intersection geometry data should be included + * at each {@link StepIntersection}. See {@link StepIntersection#geometries()} for details. + * Possible values include: + * - "motorway" + * - "trunk" + * - "primary" + * - "secondary" + * - "tertiary" + * - "unclassified" + * - "residential" + * - "service_other" + * Geometry data will be provided for each intersection along the requested route. + * The geometry format is affected by {@link RouteOptions#geometries}. + * Requires {@link RouteOptions#steps()} to be set to true. + * Be aware that enabling this option can significantly increase the response size + * and the memory required to store the response object. Use this option selectively, for example, + * if geometry is only needed for motorways, specify only "motorway". + * + * @return a comma-separated list of road classes for which intersection geometry data + * should be included + */ + @SerializedName("intersection_link_geometry") + @Nullable + public abstract String intersectionLinkGeometry(); + + /** + * Defines whether to return "access" values for roads at each {@link StepIntersection}. + * See {@link StepIntersection#access()} for details. + * Requires {@link RouteOptions#steps()} to be set to true. + * + * @return boolean representing the `intersectionLinkAccess` value + */ + @SerializedName("intersection_link_access") + @Nullable + public abstract Boolean intersectionLinkAccess(); + + /** + * Defines whether to return "elevated" status for roads at each {@link StepIntersection}. + * See {@link StepIntersection#elevated()} for details. + * Requires {@link RouteOptions#steps()} to be set to true. + * + * @return boolean representing the `intersectionLinkAccess` value + */ + @SerializedName("intersection_link_elevated") + @Nullable + public abstract Boolean intersectionLinkElevated(); + + /** + * Defines whether to return "bridge" status for roads at each {@link StepIntersection}. + * See {@link StepIntersection#bridges()} for details. + * Requires {@link RouteOptions#steps()} to be set to true. + * + * @return boolean representing the `intersectionLinkAccess` value + */ + @SerializedName("intersection_link_bridge") + @Nullable + public abstract Boolean intersectionLinkBridge(); + /** * Gson type adapter for parsing Gson to this class. * @@ -1088,6 +1158,11 @@ public URL toUrl(@NonNull String accessToken) { "suppress_voice_instruction_local_names", suppressVoiceInstructionLocalNames() ); + appendQueryParameter(sb, "intersection_link_form_of_way", intersectionLinkFormOfWay()); + appendQueryParameter(sb, "intersection_link_geometry", intersectionLinkGeometry()); + appendQueryParameter(sb, "intersection_link_access", intersectionLinkAccess()); + appendQueryParameter(sb, "intersection_link_elevated", intersectionLinkElevated()); + appendQueryParameter(sb, "intersection_link_bridge", intersectionLinkBridge()); Map unrecognized = unrecognized(); if (unrecognized != null) { @@ -2127,6 +2202,113 @@ public abstract Builder suppressVoiceInstructionLocalNames( @Nullable Boolean suppressVoiceInstructionLocalNames ); + /** + * Defines whether to return "form of way" values for roads at each {@link StepIntersection}. + * See {@link StepIntersection#formOfWay()} for details. + * Requires {@link RouteOptions#steps()} to be set to true. + * + * @param intersectionLinkFormOfWay whether to return "form of way" values + * @return this builder + */ + @NonNull + public abstract Builder intersectionLinkFormOfWay( + @Nullable Boolean intersectionLinkFormOfWay + ); + + /** + * A comma-separated list of road types for which intersection geometry data should be included + * at each {@link StepIntersection}. See {@link StepIntersection#geometries()} for details. + * Requires {@link RouteOptions#steps()} to be set to true. + * Possible values include: + * - "motorway" + * - "trunk" + * - "primary" + * - "secondary" + * - "tertiary" + * - "unclassified" + * - "residential" + * - "service_other" + * Geometry data will be provided for each intersection along the requested route. + * Be aware that enabling this option can significantly increase the response size + * and the memory required to store the response object. Use this option selectively, + * for example, if geometry is only needed for motorways, specify only "motorway". + * + * @param intersectionLinkGeometry a comma-separated list of road types for which intersection + * geometry data should be included + * @return this builder + */ + @NonNull + public abstract Builder intersectionLinkGeometry( + @Nullable String intersectionLinkGeometry + ); + + /** + * A comma-separated list of road types for which intersection geometry data should be included + * at each {@link StepIntersection}. See {@link StepIntersection#geometries()} for details. + * Requires {@link RouteOptions#steps()} to be set to true. + * Possible values include: + * - "motorway" + * - "trunk" + * - "primary" + * - "secondary" + * - "tertiary" + * - "unclassified" + * - "residential" + * - "service_other" + * Geometry data will be provided for each intersection along the requested route. + * Be aware that enabling this option can significantly increase the response size + * and the memory required to store the response object. Use this option selectively, + * for example, if geometry is only needed for motorways, specify only "motorway". + * + * @param intersectionLinkGeometry a list of road types for which intersection + * geometry data should be included + * @return this builder + */ + @NonNull + public Builder intersectionLinkGeometry(@Nullable List intersectionLinkGeometry) { + String result = FormatUtils.join(",", intersectionLinkGeometry); + return intersectionLinkGeometry(result); + } + + /** + * Defines whether to return "access" values for roads at each {@link StepIntersection}. + * See {@link StepIntersection#access()} for details. + * Requires {@link RouteOptions#steps()} to be set to true. + * + * @param intersectionLinkAccess whether to return "access" values + * @return this builder + */ + @NonNull + public abstract Builder intersectionLinkAccess( + @Nullable Boolean intersectionLinkAccess + ); + + /** + * Defines whether to return "elevated" status for roads at each {@link StepIntersection}. + * See {@link StepIntersection#elevated()} for details. + * Requires {@link RouteOptions#steps()} to be set to true. + * + * @param intersectionLinkElevated whether to return "elevated" status + * @return this builder + */ + @NonNull + public abstract Builder intersectionLinkElevated( + @Nullable Boolean intersectionLinkElevated + ); + + /** + * Defines whether to return "bridge" status for roads at each {@link StepIntersection}. + * See {@link StepIntersection#bridges()} for details. + * Requires {@link RouteOptions#steps()} to be set to true. + * + * @param intersectionLinkBridge whether to return "bridge" status + * @return this builder + */ + @NonNull + public abstract Builder intersectionLinkBridge( + @Nullable Boolean intersectionLinkBridge + ); + /** * Use this method to add request parameters, * which are not present in the model yet but are supported on the Directions API, diff --git a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/StepIntersection.java b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/StepIntersection.java index e67f396ce..eb2883fcd 100644 --- a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/StepIntersection.java +++ b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/StepIntersection.java @@ -2,6 +2,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; + import com.google.auto.value.AutoValue; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -92,6 +93,76 @@ public Point location() { @Nullable public abstract List entry(); + /** + * A list representing the "form of way" values for all roads at the step intersection. + * This list has a 1:1 correspondence with the {@link #bearings()} and {@link #entry()} lists. + * Each element is one of the following: + * - freeway, + * - multiple_carriageway, + * - single_carriageway, + * - roundabout, + * - ramp, + * - service_road, + * - pedestrian_zone, + * - unknown + * Example: + * "form_of_way": [ + * "ramp", + * "single_carriageway", + * "freeway" + * ] + * + * @return A list of form of way values for all roads at the step intersection + */ + @Nullable + @SerializedName("form_of_way") + public abstract List formOfWay(); + + /** + * A list representing the geometry of each road at the step intersection. + * This list has a 1:1 correspondence with the {@link #bearings()} and {@link #entry()} lists. + * Each value represents the geometry of a segment up to the next intersection (a SIRN segment). + * For on-route segments, the geometry is `null` except for the first and last segment of each leg. + * @return A list of geometry for all roads at the step intersection + */ + @Nullable + @SerializedName("geometries") + public abstract List geometries(); + + /** + * A list representing the access type for each road at the step intersection. + * This list has a 1:1 correspondence with the {@link #bearings()} and {@link #entry()} lists. + * Each value is one of the following: + * - 0 (none) + * - -1 (forward) + * - 1 (backward) + * - 2 (both). + * @return A list of access values for all roads at the intersection + */ + @Nullable + @SerializedName("access") + public abstract List access(); + + /** + * A list indicating whether each road at the step intersection is elevated. + * This list has a 1:1 correspondence with the {@link #bearings()} and {@link #entry()} lists. + * Each value is {@code true} if the segment is elevated, otherwise {@code false}. + * @return A list of boolean values indicating elevated status for all roads at the intersection. + */ + @Nullable + @SerializedName("elevated") + public abstract List elevated(); + + /** + * A list indicating whether each road at the step intersection is a bridge. + * This list has a 1:1 correspondence with the {@link #bearings()} and {@link #entry()} lists. + * Each value is {@code true} if the segment is a bridge, otherwise {@code false}. + * @return A list of boolean values indicating bridge status for all roads at the intersection + */ + @Nullable + @SerializedName("bridges") + public abstract List bridges(); + /** * Index into bearings/entry array. Used to calculate the bearing before the turn. Namely, the * clockwise angle from true north to the direction of travel before the maneuver/passing the @@ -360,6 +431,83 @@ public abstract static class Builder extends DirectionsJsonObject.Builder entry); + /** + * A list representing the "form of way" values for all roads at the step intersection. + * This list has a 1:1 correspondence with the {@link #bearings()} and {@link #entry()} lists. + * Each element is one of the following: + * - freeway, + * - multiple_carriageway, + * - single_carriageway, + * - roundabout, + * - ramp, + * - service_road, + * - pedestrian_zone, + * - unknown + * Example: + * "form_of_way": [ + * "ramp", + * "single_carriageway", + * "freeway" + * ] + * + * @param formOfWay a list of form of way values for all roads at the step intersection + * @return this builder for chaining options together + */ + @NonNull + public abstract Builder formOfWay(List formOfWay); + + /** + * A list representing the geometry of each road at the step intersection. + * This list has a 1:1 correspondence with the {@link #bearings()} and {@link #entry()} lists. + * Each value represents the geometry of a segment up to the next intersection (a SIRN segment). + * For on-route segments, the geometry is `null` except for the first and last segment + * of each leg. + * + * @param geometries a list of geometry for all roads at the step intersection + * @return this builder for chaining options together + */ + @NonNull + public abstract Builder geometries(List geometries); + + /** + * A list representing the access type for each road at the step intersection. + * This list has a 1:1 correspondence with the {@link #bearings()} and {@link #entry()} lists. + * Each value is one of the following: + * - 0 (none) + * - -1 (forward) + * - 1 (backward) + * - 2 (both). + * + * @param access a list of access values for all roads at the intersection + * @return this builder for chaining options together + */ + @NonNull + public abstract Builder access(List access); + + /** + * A list indicating whether each road at the step intersection is elevated. + * This list has a 1:1 correspondence with the {@link #bearings()} and {@link #entry()} lists. + * Each value is {@code true} if the segment is elevated, otherwise {@code false}. + * + * @param elevated a list of boolean values indicating elevated status for all roads + * at the intersection. + * @return this builder for chaining options together + */ + @NonNull + public abstract Builder elevated(List elevated); + + /** + * A list indicating whether each road at the step intersection is a bridge. + * This list has a 1:1 correspondence with the {@link #bearings()} and {@link #entry()} lists. + * Each value is {@code true} if the segment is a bridge, otherwise {@code false}. + * + * @param bridges a list of boolean values indicating bridge status for all roads + * at the intersection + * @return this builder for chaining options together + */ + @NonNull + public abstract Builder bridges(List bridges); + /** * Index into bearings/entry array. Used to calculate the bearing before the turn. Namely, the * clockwise angle from true north to the direction of travel before the maneuver/passing the diff --git a/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/DirectionsRouteTest.java b/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/DirectionsRouteTest.java index 6ad866760..cbf791e75 100644 --- a/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/DirectionsRouteTest.java +++ b/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/DirectionsRouteTest.java @@ -261,4 +261,105 @@ public void directionsRoute_hasLaneAttributes() throws IOException { .build(); assertEquals(access, lane.access()); } + + @Test + public void directionsRoute_hasFormOfWay() throws IOException { + String json = loadJsonFixture("directions_v5_with_toll_costs_and_lanes.json"); + RouteOptions options = RouteOptions.builder() + .profile(DirectionsCriteria.PROFILE_DRIVING_TRAFFIC) + .coordinatesList(new ArrayList() {{ + add(Point.fromLngLat(1.0, 1.0)); + add(Point.fromLngLat(2.0, 2.0)); + }}) + .build(); + String uuid = "123"; + DirectionsRoute route = DirectionsRoute.fromJson(json, options, uuid); + + final List formOfWay = route.legs().get(0).steps().get(0).intersections().get(0) + .formOfWay(); + + assertEquals(Arrays.asList("freeway", "ramp", null), formOfWay); + } + + @Test + public void directionsRoute_hasGeometries() throws IOException { + String json = loadJsonFixture("directions_v5_with_toll_costs_and_lanes.json"); + RouteOptions options = RouteOptions.builder() + .profile(DirectionsCriteria.PROFILE_DRIVING_TRAFFIC) + .coordinatesList(new ArrayList() {{ + add(Point.fromLngLat(1.0, 1.0)); + add(Point.fromLngLat(2.0, 2.0)); + }}) + .build(); + String uuid = "123"; + DirectionsRoute route = DirectionsRoute.fromJson(json, options, uuid); + + final List geometries = route.legs().get(0).steps().get(0).intersections().get(0) + .geometries(); + + final List expectedGeometries = Arrays.asList( + "k}fiyAcxhgOjCRrD?rDS~CSrDSbQ{@rIg@nFSfES~HSjMSrNRjMz@jHz@jMjCnK~CzJrD~MvG", + null, + null + ); + + assertEquals(expectedGeometries, geometries); + } + + @Test + public void directionsRoute_hasAccess() throws IOException { + String json = loadJsonFixture("directions_v5_with_toll_costs_and_lanes.json"); + RouteOptions options = RouteOptions.builder() + .profile(DirectionsCriteria.PROFILE_DRIVING_TRAFFIC) + .coordinatesList(new ArrayList() {{ + add(Point.fromLngLat(1.0, 1.0)); + add(Point.fromLngLat(2.0, 2.0)); + }}) + .build(); + String uuid = "123"; + DirectionsRoute route = DirectionsRoute.fromJson(json, options, uuid); + + assertEquals( + Arrays.asList(0, 1, null), + route.legs().get(0).steps().get(0).intersections().get(0).access() + ); + } + + @Test + public void directionsRoute_hasElevated() throws IOException { + String json = loadJsonFixture("directions_v5_with_toll_costs_and_lanes.json"); + RouteOptions options = RouteOptions.builder() + .profile(DirectionsCriteria.PROFILE_DRIVING_TRAFFIC) + .coordinatesList(new ArrayList() {{ + add(Point.fromLngLat(1.0, 1.0)); + add(Point.fromLngLat(2.0, 2.0)); + }}) + .build(); + String uuid = "123"; + DirectionsRoute route = DirectionsRoute.fromJson(json, options, uuid); + + assertEquals( + Arrays.asList(true, false, null), + route.legs().get(0).steps().get(0).intersections().get(0).elevated() + ); + } + + @Test + public void directionsRoute_hasBridges() throws IOException { + String json = loadJsonFixture("directions_v5_with_toll_costs_and_lanes.json"); + RouteOptions options = RouteOptions.builder() + .profile(DirectionsCriteria.PROFILE_DRIVING_TRAFFIC) + .coordinatesList(new ArrayList() {{ + add(Point.fromLngLat(1.0, 1.0)); + add(Point.fromLngLat(2.0, 2.0)); + }}) + .build(); + String uuid = "123"; + DirectionsRoute route = DirectionsRoute.fromJson(json, options, uuid); + + assertEquals( + Arrays.asList(false, true, null), + route.legs().get(0).steps().get(0).intersections().get(0).bridges() + ); + } } diff --git a/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/RouteOptionsTest.java b/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/RouteOptionsTest.java index 4f2ba022c..0ba4676dd 100644 --- a/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/RouteOptionsTest.java +++ b/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/RouteOptionsTest.java @@ -37,8 +37,54 @@ public class RouteOptionsTest extends TestUtils { * Always update this file when new option is introduced. */ private static final String ROUTE_OPTIONS_JSON = "route_options_v5.json"; + private static final String ROUTE_OPTIONS_URL = - "https://api.mapbox.com/directions/v5/mapbox/driving/-122.4003312,37.7736941;-122.4187529,37.7689715;-122.4255172,37.7775835?access_token=pk.token&geometries=polyline6&alternatives=false&overview=full&radiuses=%3Bunlimited%3B5.1&steps=true&avoid_maneuver_radius=200.0&bearings=0%2C90%3B90%2C0%3B&layers=-42%3B%3B0&continue_straight=false&annotations=congestion%2Cdistance%2Cduration&language=ru&roundabout_exits=false&voice_instructions=true&banner_instructions=true&voice_units=metric&exclude=toll%2Cferry%2Cpoint%2811.0+-22.0%29&include=hot%2Chov2&approaches=%3Bcurb%3B&waypoints=0%3B1%3B2&waypoint_names=%3BSerangoon+Garden+Market+%26+Food+Centre%3BFunky+%26nAmE*&waypoint_targets=%3B12.2%2C21.2%3B&enable_refresh=true&walking_speed=5.11&walkway_bias=-0.2&alley_bias=0.75&snapping_include_closures=%3Bfalse%3Btrue&snapping_include_static_closures=true%3B%3Bfalse&arrive_by=2021-01-01%27T%2701%3A01&depart_at=2021-02-02%27T%2702%3A02&max_height=1.5&max_width=1.4&max_weight=2.9&compute_toll_cost=true&waypoints_per_route=true&metadata=true&payment_methods=general&suppress_voice_instruction_local_names=true"; + "https://api.mapbox.com/directions/v5/mapbox/driving/" + + "-122.4003312,37.7736941;-122.4187529,37.7689715;-122.4255172,37.7775835" + + "?access_token=pk.token" + + "&geometries=polyline6" + + "&alternatives=false" + + "&overview=full" + + "&radiuses=%3Bunlimited%3B5.1" + + "&steps=true" + + "&avoid_maneuver_radius=200.0" + + "&bearings=0%2C90%3B90%2C0%3B" + + "&layers=-42%3B%3B0" + + "&continue_straight=false" + + "&annotations=congestion%2Cdistance%2Cduration" + + "&language=ru" + + "&roundabout_exits=false" + + "&voice_instructions=true" + + "&banner_instructions=true" + + "&voice_units=metric" + + "&exclude=toll%2Cferry%2Cpoint%2811.0+-22.0%29" + + "&include=hot%2Chov2" + + "&approaches=%3Bcurb%3B" + + "&waypoints=0%3B1%3B2" + + "&waypoint_names=%3BSerangoon+Garden+Market+%26+Food+Centre%3BFunky+%26nAmE*" + + "&waypoint_targets=%3B12.2%2C21.2%3B" + + "&enable_refresh=true" + + "&walking_speed=5.11" + + "&walkway_bias=-0.2" + + "&alley_bias=0.75" + + "&snapping_include_closures=%3Bfalse%3Btrue" + + "&snapping_include_static_closures=true%3B%3Bfalse" + + "&arrive_by=2021-01-01%27T%2701%3A01" + + "&depart_at=2021-02-02%27T%2702%3A02" + + "&max_height=1.5" + + "&max_width=1.4" + + "&max_weight=2.9" + + "&compute_toll_cost=true" + + "&waypoints_per_route=true" + + "&metadata=true" + + "&payment_methods=general" + + "&suppress_voice_instruction_local_names=true" + + "&intersection_link_form_of_way=true" + + "&intersection_link_geometry=motorway%2Ctrunk%2Cprimary" + + "&intersection_link_access=true" + + "&intersection_link_elevated=true" + + "&intersection_link_bridge=true"; + private static final String ACCESS_TOKEN = "pk.token"; private final String optionsJson = loadJsonFixture(ROUTE_OPTIONS_JSON); @@ -364,6 +410,36 @@ public void waypointsPerRouteAreValid_fromJson() { assertEquals(true, routeOptions.waypointsPerRoute()); } + @Test + public void intersectionLinkGeometryAreValid_fromJson() { + RouteOptions routeOptions = RouteOptions.fromJson(optionsJson); + assertEquals("motorway,trunk,primary", routeOptions.intersectionLinkGeometry()); + } + + @Test + public void intersectionLinkFormOfWayAreValid_fromJson() { + RouteOptions routeOptions = RouteOptions.fromJson(optionsJson); + assertEquals(true, routeOptions.intersectionLinkFormOfWay()); + } + + @Test + public void intersectionLinkAccessAreValid_fromJson() { + RouteOptions routeOptions = RouteOptions.fromJson(optionsJson); + assertEquals(true, routeOptions.intersectionLinkAccess()); + } + + @Test + public void intersectionLinkElevatedAreValid_fromJson() { + RouteOptions routeOptions = RouteOptions.fromJson(optionsJson); + assertEquals(true, routeOptions.intersectionLinkElevated()); + } + + @Test + public void intersectionLinkBridgeAreValid_fromJson() { + RouteOptions routeOptions = RouteOptions.fromJson(optionsJson); + assertEquals(true, routeOptions.intersectionLinkBridge()); + } + @Test public void defaultTollCost() { RouteOptions options = defaultRouteOptions(); @@ -385,6 +461,18 @@ public void defaultWaypointsPerRoute() { assertNull(options.waypointsPerRoute()); } + @Test + public void defaultIntersectionLinkFormOfWay() { + RouteOptions options = defaultRouteOptions(); + assertNull(options.intersectionLinkFormOfWay()); + } + + @Test + public void defaultIntersectionLinkGeometry() { + RouteOptions options = defaultRouteOptions(); + assertNull(options.intersectionLinkGeometry()); + } + @Test public void routeOptions_toJson() { RouteOptions options = routeOptions(); @@ -1128,6 +1216,11 @@ private RouteOptions routeOptions() { .waypointsPerRoute(true) .paymentMethods(DirectionsCriteria.PAYMENT_METHOD_GENERAL) .suppressVoiceInstructionLocalNames(true) + .intersectionLinkFormOfWay(true) + .intersectionLinkGeometry("motorway,trunk,primary") + .intersectionLinkAccess(true) + .intersectionLinkElevated(true) + .intersectionLinkBridge(true) .build(); } @@ -1237,6 +1330,11 @@ private RouteOptions routeOptionsList() { .waypointsPerRoute(true) .suppressVoiceInstructionLocalNames(true) .paymentMethodsList(Arrays.asList(DirectionsCriteria.PAYMENT_METHOD_GENERAL)) + .intersectionLinkFormOfWay(true) + .intersectionLinkAccess(true) + .intersectionLinkElevated(true) + .intersectionLinkBridge(true) + .intersectionLinkGeometry(Arrays.asList("motorway", "trunk", "primary")) .build(); } } diff --git a/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/StepIntersectionTest.java b/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/StepIntersectionTest.java index 4d1504c84..1cec5f9de 100644 --- a/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/StepIntersectionTest.java +++ b/services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/StepIntersectionTest.java @@ -1,16 +1,18 @@ package com.mapbox.api.directions.v5.models; -import static junit.framework.TestCase.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - import com.mapbox.core.TestUtils; import com.mapbox.geojson.Point; +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNull; + import org.junit.Assert; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import org.junit.Test; import java.util.Arrays; +import java.util.List; public class StepIntersectionTest extends TestUtils { @@ -246,4 +248,175 @@ public void testNullMergingArea() { String jsonStr = stepIntersection.toJson(); compareJson(stepIntersectionJsonString, jsonStr); } + + @Test + public void testFormOfWay() { + final String stepIntersectionJsonString = "{" + + "\"location\": [ 13.426579, 52.508068 ]," + + "\"form_of_way\": [\n" + + " \"freeway\",\n" + + " \"roundabout\",\n" + + " \"ramp\",\n" + + " null\n" + + "]" + + "}"; + + final StepIntersection stepIntersection = StepIntersection.fromJson(stepIntersectionJsonString); + + final List formOfWay = Arrays.asList( + "freeway", "roundabout", "ramp", null + ); + + assertEquals(formOfWay, stepIntersection.formOfWay()); + + final String jsonStr = stepIntersection.toJson(); + compareJson(stepIntersectionJsonString, jsonStr); + } + + @Test + public void testNullFormOfWay() { + final String stepIntersectionJsonString = "{" + + "\"location\": [ 13.426579, 52.508068 ]" + + "}"; + + final StepIntersection stepIntersection = StepIntersection.fromJson(stepIntersectionJsonString); + assertNull(stepIntersection.formOfWay()); + } + + @Test + public void testGeometries() { + final String stepIntersectionJsonString = "{" + + "\"location\": [ 13.426579, 52.508068 ]," + + "\"geometries\": [\n" + + " \"{{vacBwuenX?^?|OAzXBdP\",\n" + + " \"}xfbcB_yjkXcEdAcF`KwClEyH|NoQz[iOdUqOhSeT|TgH`FyHnFuKbF}ChAcFhBoGpAqFXeIXeEHuVl@\",\n" + + " null\n" + + "]" + + "}"; + + final StepIntersection stepIntersection = StepIntersection.fromJson(stepIntersectionJsonString); + + final List geometries = Arrays.asList( + "{{vacBwuenX?^?|OAzXBdP", + "}xfbcB_yjkXcEdAcF`KwClEyH|NoQz[iOdUqOhSeT|TgH`FyHnFuKbF}ChAcFhBoGpAqFXeIXeEHuVl@", + null + ); + + assertEquals(geometries, stepIntersection.geometries()); + + final String jsonStr = stepIntersection.toJson(); + compareJson(stepIntersectionJsonString, jsonStr); + } + + @Test + public void testNullGeometries() { + String stepIntersectionJsonString = "{" + + "\"location\": [ 13.426579, 52.508068 ]" + + "}"; + + final StepIntersection stepIntersection = StepIntersection.fromJson(stepIntersectionJsonString); + assertNull(stepIntersection.geometries()); + } + + @Test + public void testAccess() { + final String stepIntersectionJsonString = "{" + + "\"location\": [ 13.426579, 52.508068 ]," + + "\"access\": [\n" + + " 0,\n" + + " -1,\n" + + " 1,\n" + + " 2,\n" + + " null" + + "]" + + "}"; + + final StepIntersection stepIntersection = StepIntersection.fromJson(stepIntersectionJsonString); + + final List access = Arrays.asList( + 0, -1, 1, 2, null + ); + + assertEquals(access, stepIntersection.access()); + + final String jsonStr = stepIntersection.toJson(); + compareJson(stepIntersectionJsonString, jsonStr); + } + + @Test + public void testNullAccess() { + String stepIntersectionJsonString = "{" + + "\"location\": [ 13.426579, 52.508068 ]" + + "}"; + + final StepIntersection stepIntersection = StepIntersection.fromJson(stepIntersectionJsonString); + assertNull(stepIntersection.access()); + } + + @Test + public void testElevated() { + final String stepIntersectionJsonString = "{" + + "\"location\": [ 13.426579, 52.508068 ]," + + "\"elevated\": [\n" + + " true,\n" + + " false,\n" + + " null" + + "]" + + "}"; + + final StepIntersection stepIntersection = StepIntersection.fromJson(stepIntersectionJsonString); + + final List elevated = Arrays.asList( + true, false, null + ); + + assertEquals(elevated, stepIntersection.elevated()); + + final String jsonStr = stepIntersection.toJson(); + compareJson(stepIntersectionJsonString, jsonStr); + } + + @Test + public void testNullElevated() { + String stepIntersectionJsonString = "{" + + "\"location\": [ 13.426579, 52.508068 ]" + + "}"; + + final StepIntersection stepIntersection = StepIntersection.fromJson(stepIntersectionJsonString); + assertNull(stepIntersection.elevated()); + } + + @Test + public void testBridges() { + final String stepIntersectionJsonString = "{" + + "\"location\": [ 13.426579, 52.508068 ]," + + "\"bridges\": [\n" + + " true,\n" + + " false,\n" + + " true,\n" + + " null" + + "]" + + "}"; + + final StepIntersection stepIntersection = StepIntersection.fromJson(stepIntersectionJsonString); + + final List bridge = Arrays.asList( + true, false, true, null + ); + + assertEquals(bridge, stepIntersection.bridges()); + + final String jsonStr = stepIntersection.toJson(); + compareJson(stepIntersectionJsonString, jsonStr); + } + + @Test + public void testNullBridges() { + String stepIntersectionJsonString = "{" + + "\"location\": [ 13.426579, 52.508068 ]" + + "}"; + + final StepIntersection stepIntersection = StepIntersection.fromJson(stepIntersectionJsonString); + assertNull(stepIntersection.bridges()); + } } diff --git a/services-directions-models/src/test/resources/directions_v5_with_toll_costs_and_lanes.json b/services-directions-models/src/test/resources/directions_v5_with_toll_costs_and_lanes.json index 17a98c182..b9e7f1e18 100644 --- a/services-directions-models/src/test/resources/directions_v5_with_toll_costs_and_lanes.json +++ b/services-directions-models/src/test/resources/directions_v5_with_toll_costs_and_lanes.json @@ -143,10 +143,37 @@ } ], "entry": [ - true + true, + true, + false ], "bearings": [ - 198 + 90, + 180, + 270 + ], + "geometries": [ + "k}fiyAcxhgOjCRrD?rDS~CSrDSbQ{@rIg@nFSfES~HSjMSrNRjMz@jHz@jMjCnK~CzJrD~MvG", + null, + null + ], + "form_of_way": [ + "freeway", "ramp", null + ], + "access": [ + 0, + 1, + null + ], + "elevated": [ + true, + false, + null + ], + "bridges": [ + false, + true, + null ], "duration": 3.749, "mapbox_streets_v8": { diff --git a/services-directions-models/src/test/resources/route_options_v5.json b/services-directions-models/src/test/resources/route_options_v5.json index 28998ec51..6e3db6b60 100644 --- a/services-directions-models/src/test/resources/route_options_v5.json +++ b/services-directions-models/src/test/resources/route_options_v5.json @@ -39,5 +39,10 @@ "waypoints_per_route": true, "compute_toll_cost": true, "payment_methods": "general", - "suppress_voice_instruction_local_names": true -} \ No newline at end of file + "suppress_voice_instruction_local_names": true, + "intersection_link_form_of_way": true, + "intersection_link_geometry": "motorway,trunk,primary", + "intersection_link_access": true, + "intersection_link_elevated": true, + "intersection_link_bridge": true +} From 2d0f464bb8e269278c486fc8a563b8a7996404ee Mon Sep 17 00:00:00 2001 From: dzmitryfomchyn Date: Thu, 31 Jul 2025 18:36:50 +0200 Subject: [PATCH 3/5] Add BRITISH_IMPERIAL voice unit --- CHANGELOG.md | 1 + .../mapbox/api/directions/v5/DirectionsCriteria.java | 10 +++++++++- .../mapbox/api/directions/v5/models/RouteOptions.java | 6 ++++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c8198359..d17f31d2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ Mapbox welcomes participation and contributions from everyone. - Added `StepIntersection#access` property which provides a list representing the access type for each road at the step intersection. [#1611](https://github.com/mapbox/mapbox-java/pull/1611) - Added `StepIntersection#elevated` property which provides a list indicating whether each road at the step intersection is elevated. [#1611](https://github.com/mapbox/mapbox-java/pull/1611) - Added `StepIntersection#bridge` property which provides a list indicating whether each road at the step intersection is a bridge. [#1611](https://github.com/mapbox/mapbox-java/pull/1611) +- Added a new voice unit value: `DirectionsCriteria#BRITISH_IMPERIAL`. This value is now included in `DirectionsCriteria#VoiceUnitCriteria`. [#1611](https://github.com/mapbox/mapbox-java/pull/1611) ### v7.5.0 - July 31, 2025 diff --git a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/DirectionsCriteria.java b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/DirectionsCriteria.java index c8be202d3..de73a4c65 100644 --- a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/DirectionsCriteria.java +++ b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/DirectionsCriteria.java @@ -239,6 +239,13 @@ public final class DirectionsCriteria { */ public static final String METRIC = "metric"; + /** + * Change the units to british imperial for voice and visual information. + * Note that this won't change other results such as raw distance measurements which will + * always be returned in meters. + */ + public static final String BRITISH_IMPERIAL = "british_imperial"; + /** * Returned route starts at the first provided coordinate in the list. Used specifically for the * Optimization API. @@ -594,7 +601,8 @@ private DirectionsCriteria() { @Retention(RetentionPolicy.CLASS) @StringDef( { IMPERIAL, - METRIC + METRIC, + BRITISH_IMPERIAL }) public @interface VoiceUnitCriteria { } diff --git a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java index 9afba4106..d2db62c75 100644 --- a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java +++ b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java @@ -506,7 +506,8 @@ public List includeList() { /** * A type of units to return in the text for voice instructions. - * Can be {@link DirectionsCriteria#IMPERIAL} (default) or {@link DirectionsCriteria#METRIC}. + * Can be {@link DirectionsCriteria#IMPERIAL} (default), {@link DirectionsCriteria#METRIC}, + * or {@link DirectionsCriteria#BRITISH_IMPERIAL}. * Must be used in conjunction with {@link RouteOptions#steps()}=true and * {@link RouteOptions#steps()}=true * and {@link RouteOptions#voiceInstructions()}=true. @@ -1628,7 +1629,8 @@ public Builder annotationsList(@Nullable List annotations) { /** * A type of units to return in the text for voice instructions. - * Can be {@link DirectionsCriteria#IMPERIAL} (default) or {@link DirectionsCriteria#METRIC}. + * Can be {@link DirectionsCriteria#IMPERIAL} (default), {@link DirectionsCriteria#METRIC}, + * or {@link DirectionsCriteria#BRITISH_IMPERIAL}. * Must be used in conjunction with {@link RouteOptions#steps()}=true and * {@link RouteOptions#steps()}=true * and {@link RouteOptions#voiceInstructions()}=true. From 8bb25f3b622982605b67899a7cbd1e4ac18bd0e1 Mon Sep 17 00:00:00 2001 From: dzmitryfomchyn Date: Thu, 31 Jul 2025 18:55:24 +0200 Subject: [PATCH 4/5] Fix style --- .../v5/models/StepIntersection.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/StepIntersection.java b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/StepIntersection.java index eb2883fcd..f70eb94c8 100644 --- a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/StepIntersection.java +++ b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/StepIntersection.java @@ -52,7 +52,7 @@ public Point location() { */ @NonNull @SerializedName("location") - @SuppressWarnings( {"mutable", "WeakerAccess"}) + @SuppressWarnings({"mutable", "WeakerAccess"}) protected abstract double[] rawLocation(); /** @@ -107,9 +107,9 @@ public Point location() { * - unknown * Example: * "form_of_way": [ - * "ramp", - * "single_carriageway", - * "freeway" + * "ramp", + * "single_carriageway", + * "freeway" * ] * * @return A list of form of way values for all roads at the step intersection @@ -122,7 +122,9 @@ public Point location() { * A list representing the geometry of each road at the step intersection. * This list has a 1:1 correspondence with the {@link #bearings()} and {@link #entry()} lists. * Each value represents the geometry of a segment up to the next intersection (a SIRN segment). - * For on-route segments, the geometry is `null` except for the first and last segment of each leg. + * For on-route segments, the geometry is `null` except for the first and last segment + * of each leg. + * * @return A list of geometry for all roads at the step intersection */ @Nullable @@ -137,6 +139,7 @@ public Point location() { * - -1 (forward) * - 1 (backward) * - 2 (both). + * * @return A list of access values for all roads at the intersection */ @Nullable @@ -147,6 +150,7 @@ public Point location() { * A list indicating whether each road at the step intersection is elevated. * This list has a 1:1 correspondence with the {@link #bearings()} and {@link #entry()} lists. * Each value is {@code true} if the segment is elevated, otherwise {@code false}. + * * @return A list of boolean values indicating elevated status for all roads at the intersection. */ @Nullable @@ -157,6 +161,7 @@ public Point location() { * A list indicating whether each road at the step intersection is a bridge. * This list has a 1:1 correspondence with the {@link #bearings()} and {@link #entry()} lists. * Each value is {@code true} if the segment is a bridge, otherwise {@code false}. + * * @return A list of boolean values indicating bridge status for all roads at the intersection */ @Nullable @@ -445,9 +450,9 @@ public abstract static class Builder extends DirectionsJsonObject.Builder Date: Fri, 1 Aug 2025 11:06:38 +0200 Subject: [PATCH 5/5] Address review comments --- .../com/mapbox/api/directions/v5/models/RouteOptions.java | 4 ++-- .../com/mapbox/api/directions/v5/models/StepIntersection.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java index d2db62c75..d5ed873ee 100644 --- a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java +++ b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java @@ -1000,7 +1000,7 @@ public List paymentMethodsList() { * See {@link StepIntersection#elevated()} for details. * Requires {@link RouteOptions#steps()} to be set to true. * - * @return boolean representing the `intersectionLinkAccess` value + * @return boolean representing the `intersectionLinkElevated` value */ @SerializedName("intersection_link_elevated") @Nullable @@ -1011,7 +1011,7 @@ public List paymentMethodsList() { * See {@link StepIntersection#bridges()} for details. * Requires {@link RouteOptions#steps()} to be set to true. * - * @return boolean representing the `intersectionLinkAccess` value + * @return boolean representing the `intersectionLinkBridge` value */ @SerializedName("intersection_link_bridge") @Nullable diff --git a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/StepIntersection.java b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/StepIntersection.java index f70eb94c8..df2de1ed6 100644 --- a/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/StepIntersection.java +++ b/services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/StepIntersection.java @@ -121,7 +121,7 @@ public Point location() { /** * A list representing the geometry of each road at the step intersection. * This list has a 1:1 correspondence with the {@link #bearings()} and {@link #entry()} lists. - * Each value represents the geometry of a segment up to the next intersection (a SIRN segment). + * Each value represents the geometry of a segment up to the next intersection. * For on-route segments, the geometry is `null` except for the first and last segment * of each leg. * @@ -464,7 +464,7 @@ public abstract static class Builder extends DirectionsJsonObject.Builder