Skip to content

Commit f56c439

Browse files
authored
Exclude waypoints from routing (#1362)
1 parent f8599bc commit f56c439

7 files changed

Lines changed: 624 additions & 33 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Mapbox welcomes participation and contributions from everyone.
44

55
### main
66
- Exposed `viaWaypoints` in `RouteLeg` [#1364](https://github.com/mapbox/mapbox-java/pull/1364)
7+
- Added an API for providing points to exclude. [#1362](https://github.com/mapbox/mapbox-java/pull/1362)
78

89
### v6.3.0-beta.1 - January 28, 2021
910
- Exposed [turf.lineIntersect](https://turfjs.org/docs/#lineIntersect) via `TurfMisc#lineIntersect` using an algorithm with O(nm) time complexity which should suite small to medium sized geometries until a more performant solution is implemented. [#1348](https://github.com/mapbox/mapbox-java/pull/1348)

services-directions-models/src/main/java/com/mapbox/api/directions/v5/DirectionsCriteria.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ private DirectionsCriteria() {
340340
* @since 3.0.0
341341
*/
342342
@Retention(RetentionPolicy.CLASS)
343+
// Please update Exclude.VALID_EXCLUDE_CRITERIA adding new type of exclude
343344
@StringDef( {
344345
EXCLUDE_FERRY,
345346
EXCLUDE_MOTORWAY,
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
package com.mapbox.api.directions.v5.models;
2+
3+
import androidx.annotation.NonNull;
4+
import androidx.annotation.Nullable;
5+
import com.google.auto.value.AutoValue;
6+
import com.mapbox.api.directions.v5.DirectionsCriteria;
7+
import com.mapbox.api.directions.v5.utils.ParseUtils;
8+
import com.mapbox.geojson.Point;
9+
10+
import java.util.ArrayList;
11+
import java.util.HashSet;
12+
import java.util.List;
13+
import java.util.Objects;
14+
import java.util.Set;
15+
16+
/**
17+
* Defines excludes for {@link RouteOptions.Builder#excludeObject(Exclude)}.
18+
*
19+
* This class provides type-safe way to read and build {@link RouteOptions#exclude()} parameter.
20+
*
21+
* All properties are strictly categorized after parsing. Unknown data types or flags
22+
* are ignored. If you want to work with exclude criteria which is not yet supported,
23+
* consider using raw {@link RouteOptions#exclude()} directly.
24+
*/
25+
@AutoValue
26+
public abstract class Exclude {
27+
28+
/**
29+
* Build a new instance of {@link Exclude}. Nothing is excluded by default.
30+
*/
31+
@NonNull
32+
public static Builder builder() {
33+
return new AutoValue_Exclude.Builder();
34+
}
35+
36+
/**
37+
* Exclude certain road types from routing. The default is to not exclude anything from the
38+
* profile selected. The following exclude flags are available for each profile:
39+
* <p>
40+
* {@link DirectionsCriteria#PROFILE_DRIVING}: One of {@link DirectionsCriteria#EXCLUDE_TOLL},
41+
* {@link DirectionsCriteria#EXCLUDE_MOTORWAY}, or {@link DirectionsCriteria#EXCLUDE_FERRY}.
42+
* <p>
43+
* {@link DirectionsCriteria#PROFILE_DRIVING_TRAFFIC}: One of
44+
* {@link DirectionsCriteria#EXCLUDE_TOLL}, {@link DirectionsCriteria#EXCLUDE_MOTORWAY}, or
45+
* {@link DirectionsCriteria#EXCLUDE_FERRY}.
46+
* <p>
47+
* {@link DirectionsCriteria#PROFILE_WALKING}: No excludes supported
48+
* <p>
49+
* {@link DirectionsCriteria#PROFILE_CYCLING}: {@link DirectionsCriteria#EXCLUDE_FERRY}
50+
*
51+
* @return a list of strings matching one
52+
* of the {@link DirectionsCriteria.ExcludeCriteria} exclusions
53+
*/
54+
@Nullable
55+
public abstract List<String> criteria();
56+
57+
/**
58+
* Exclude certain points from routing. The default is to not exclude anything.
59+
*
60+
* @return a list of points excluded from the routing.
61+
*/
62+
@Nullable
63+
public abstract List<Point> points();
64+
65+
/**
66+
* Use this builder to build an {@link Exclude} object.
67+
*/
68+
@AutoValue.Builder
69+
public abstract static class Builder {
70+
71+
/**
72+
* Exclude certain road types from routing. The default is to not exclude anything from the
73+
* profile selected. The following exclude flags are available for each profile:
74+
* <p>
75+
* {@link DirectionsCriteria#PROFILE_DRIVING}: One of {@link DirectionsCriteria#EXCLUDE_TOLL},
76+
* {@link DirectionsCriteria#EXCLUDE_MOTORWAY}, or {@link DirectionsCriteria#EXCLUDE_FERRY}.
77+
* <p>
78+
* {@link DirectionsCriteria#PROFILE_DRIVING_TRAFFIC}: One of
79+
* {@link DirectionsCriteria#EXCLUDE_TOLL}, {@link DirectionsCriteria#EXCLUDE_MOTORWAY}, or
80+
* {@link DirectionsCriteria#EXCLUDE_FERRY}.
81+
* <p>
82+
* {@link DirectionsCriteria#PROFILE_WALKING}: No excludes supported
83+
* <p>
84+
* {@link DirectionsCriteria#PROFILE_CYCLING}: {@link DirectionsCriteria#EXCLUDE_FERRY}
85+
*
86+
* @param criteria a list of exclude criteria
87+
* matching {@link DirectionsCriteria.ExcludeCriteria}
88+
* @return this builder.
89+
*/
90+
public abstract Builder criteria(@Nullable List<String> criteria);
91+
92+
/**
93+
* Exclude certain points from routing. The default is to not exclude anything.
94+
*
95+
* @param points a list of points to exclude.
96+
* @return this builder.
97+
*/
98+
public abstract Builder points(@Nullable List<Point> points);
99+
100+
/**
101+
* Builds the object.
102+
*
103+
* @return a new instance of {@link Exclude}
104+
*/
105+
public abstract Exclude build();
106+
}
107+
108+
@Nullable
109+
static Exclude fromUrlQueryParameter(@Nullable String queryParameter) {
110+
if (queryParameter == null || Objects.equals(queryParameter, "")) {
111+
return null;
112+
}
113+
114+
ArrayList<Point> points = new ArrayList<>();
115+
ArrayList<String> criteria = new ArrayList<>();
116+
117+
List<String> excludeItems = ParseUtils.parseToStrings(queryParameter, ",");
118+
if (excludeItems != null) {
119+
for (String excludeItem : excludeItems) {
120+
if (excludeItem.startsWith("point(") && excludeItem.endsWith(")")) {
121+
Point point = parsePointOrNull(excludeItem);
122+
if (point != null) {
123+
points.add(point);
124+
}
125+
} else if (VALID_EXCLUDE_CRITERIA.contains(excludeItem)) {
126+
criteria.add(excludeItem);
127+
}
128+
}
129+
}
130+
131+
if (criteria.size() == 0) {
132+
criteria = null;
133+
}
134+
if (points.size() == 0) {
135+
points = null;
136+
}
137+
if (criteria == null && points == null) {
138+
return null;
139+
}
140+
141+
return Exclude.builder()
142+
.criteria(criteria)
143+
.points(points)
144+
.build();
145+
}
146+
147+
@Nullable
148+
String toUrlQueryParameter() {
149+
if (points() == null && criteria() == null) {
150+
return null;
151+
}
152+
153+
StringBuilder result = new StringBuilder();
154+
155+
appendPoints(result);
156+
appendCriterias(result);
157+
158+
return result.toString();
159+
}
160+
161+
private void appendCriterias(StringBuilder result) {
162+
if (criteria() != null) {
163+
for (String item : criteria()) {
164+
if (result.length() != 0) {
165+
result.append(',');
166+
}
167+
result.append(item);
168+
}
169+
}
170+
}
171+
172+
private void appendPoints(StringBuilder result) {
173+
if (points() != null) {
174+
for (Point point : points()) {
175+
if (result.length() != 0) {
176+
result.append(",");
177+
}
178+
appendPoint(result, point);
179+
}
180+
}
181+
}
182+
183+
@Nullable
184+
private static Point parsePointOrNull(String point) {
185+
int delimiter = point.indexOf(' ');
186+
if (delimiter != -1) {
187+
String longitude = point.substring(6, delimiter);
188+
String latitude = point.substring(delimiter + 1, point.length() - 1);
189+
try {
190+
return Point.fromLngLat(
191+
Double.parseDouble(longitude),
192+
Double.parseDouble(latitude)
193+
);
194+
} catch (NumberFormatException numberFormatError) {
195+
return null;
196+
}
197+
} else {
198+
return null;
199+
}
200+
}
201+
202+
private void appendPoint(StringBuilder result, Point point) {
203+
result.append("point(")
204+
.append(point.longitude())
205+
.append(' ')
206+
.append(point.latitude())
207+
.append(')');
208+
}
209+
210+
private static final Set<String> VALID_EXCLUDE_CRITERIA = new HashSet<String>() {
211+
{
212+
add(DirectionsCriteria.EXCLUDE_FERRY);
213+
add(DirectionsCriteria.EXCLUDE_MOTORWAY);
214+
add(DirectionsCriteria.EXCLUDE_TOLL);
215+
add(DirectionsCriteria.EXCLUDE_TUNNEL);
216+
add(DirectionsCriteria.EXCLUDE_RESTRICTED);
217+
add(DirectionsCriteria.EXCLUDE_CASH_ONLY_TOLLS);
218+
add(DirectionsCriteria.EXCLUDE_UNPAVED);
219+
}
220+
};
221+
}

services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -356,8 +356,8 @@ public List<String> annotationsList() {
356356
}
357357

358358
/**
359-
* Exclude certain road types from routing. The default is to not exclude anything from the
360-
* profile selected. The following exclude flags are available for each profile:
359+
* Exclude certain road types or points from routing. The default is to not exclude anything
360+
* from the profile selected. The following exclude flags are available for each profile:
361361
* <p>
362362
* {@link DirectionsCriteria#PROFILE_DRIVING}: One of {@link DirectionsCriteria#EXCLUDE_TOLL},
363363
* {@link DirectionsCriteria#EXCLUDE_MOTORWAY}, or {@link DirectionsCriteria#EXCLUDE_FERRY}.
@@ -370,14 +370,17 @@ public List<String> annotationsList() {
370370
* <p>
371371
* {@link DirectionsCriteria#PROFILE_CYCLING}: {@link DirectionsCriteria#EXCLUDE_FERRY}
372372
*
373-
* @return a string matching one of the {@link DirectionsCriteria.ExcludeCriteria} exclusions
373+
* Excluded points are formatted like: point(longitude latitude)
374+
*
375+
* @return a comma separated string where each element matches one of
376+
* the {@link DirectionsCriteria.ExcludeCriteria} exclusion or a point
374377
*/
375378
@Nullable
376379
public abstract String exclude();
377380

378381
/**
379-
* Exclude certain road types from routing. The default is to not exclude anything from the
380-
* profile selected. The following exclude flags are available for each profile:
382+
* Exclude certain road types and points from routing. The default is to not exclude anything
383+
* from the profile selected. The following exclude flags are available for each profile:
381384
* <p>
382385
* {@link DirectionsCriteria#PROFILE_DRIVING}: One of {@link DirectionsCriteria#EXCLUDE_TOLL},
383386
* {@link DirectionsCriteria#EXCLUDE_MOTORWAY}, or {@link DirectionsCriteria#EXCLUDE_FERRY}.
@@ -390,13 +393,28 @@ public List<String> annotationsList() {
390393
* <p>
391394
* {@link DirectionsCriteria#PROFILE_CYCLING}: {@link DirectionsCriteria#EXCLUDE_FERRY}
392395
*
393-
* @return a string matching one of the {@link DirectionsCriteria.ExcludeCriteria} exclusions
396+
* Excluded points are formatted like: point(longitude latitude)
397+
*
398+
* @return a list of strings where each element matches one of the
399+
* {@link DirectionsCriteria.ExcludeCriteria} exclusion or a point
394400
*/
395401
@Nullable
396402
public List<String> excludeList() {
397403
return ParseUtils.parseToStrings(exclude(), ",");
398404
}
399405

406+
/**
407+
* Exclude certain road types and points from routing. The default is to not exclude anything
408+
* from the profile selected.
409+
*
410+
* Exclude object may not provide all features that are currently present by Direction API.
411+
* See {@link Exclude} for more details.
412+
*/
413+
@Nullable
414+
public Exclude excludeObject() {
415+
return Exclude.fromUrlQueryParameter(exclude());
416+
}
417+
400418
/**
401419
* Include certain road types in routing. By default, none of the road types listed below
402420
* are included. The following include flags are available for each profile:
@@ -1411,8 +1429,8 @@ public Builder annotationsList(@Nullable List<String> annotations) {
14111429
public abstract Builder voiceUnits(@Nullable String voiceUnits);
14121430

14131431
/**
1414-
* Exclude certain road types from routing. The default is to not exclude anything from the
1415-
* profile selected. The following exclude flags are available for each profile:
1432+
* Exclude certain road types or points from routing. The default is to not exclude anything
1433+
* from the profile selected. The following exclude flags are available for each profile:
14161434
* <p>
14171435
* {@link DirectionsCriteria#PROFILE_DRIVING}: One of {@link DirectionsCriteria#EXCLUDE_TOLL},
14181436
* {@link DirectionsCriteria#EXCLUDE_MOTORWAY}, or {@link DirectionsCriteria#EXCLUDE_FERRY}.
@@ -1425,15 +1443,17 @@ public Builder annotationsList(@Nullable List<String> annotations) {
14251443
* <p>
14261444
* {@link DirectionsCriteria#PROFILE_CYCLING}: {@link DirectionsCriteria#EXCLUDE_FERRY}
14271445
*
1428-
* @param exclude a string matching one of the {@link DirectionsCriteria.ExcludeCriteria}
1429-
* exclusions
1446+
* Use following format to exclude a point: point(longitude latitude)
1447+
*
1448+
* @param exclude a comma separated string. Each value matches one of
1449+
* the {@link DirectionsCriteria.ExcludeCriteria} exclusions or point format.
14301450
* @return this builder for chaining options together
14311451
*/
14321452
@NonNull
14331453
public abstract Builder exclude(@Nullable @DirectionsCriteria.ExcludeCriteria String exclude);
14341454

14351455
/**
1436-
* Exclude certain road types from routing.
1456+
* Exclude certain road types or points from routing.
14371457
* The default is to not exclude anything from the profile selected.
14381458
* The following exclude flags are available for each profile:
14391459
* <p>
@@ -1448,6 +1468,8 @@ public Builder annotationsList(@Nullable List<String> annotations) {
14481468
* <p>
14491469
* {@link DirectionsCriteria#PROFILE_CYCLING}: {@link DirectionsCriteria#EXCLUDE_FERRY}
14501470
*
1471+
* Use following format to exclude a point: point(longitude latitude)
1472+
*
14511473
* @param exclude a list of exclude that were used during the request
14521474
* @return this builder for chaining options together
14531475
*/
@@ -1460,6 +1482,27 @@ public Builder excludeList(@Nullable List<String> exclude) {
14601482
return this;
14611483
}
14621484

1485+
/**
1486+
* Exclude certain road types or points from routing.
1487+
* The default is to not exclude anything from the profile selected.
1488+
*
1489+
* Exclude object may not provide all features that are currently present by Direction API.
1490+
* See {@link Exclude} for more details.
1491+
*
1492+
* @param exclude an object of excludes that are used during the request.
1493+
* Use {@link Exclude.Builder} to build exclude.
1494+
* @return this builder for chaining options together
1495+
*/
1496+
@NonNull
1497+
public Builder excludeObject(@Nullable Exclude exclude) {
1498+
if (exclude != null) {
1499+
exclude(exclude.toUrlQueryParameter());
1500+
} else {
1501+
exclude(null);
1502+
}
1503+
return this;
1504+
}
1505+
14631506
/**
14641507
* Include certain road types in routing. By default, none of the road types listed below
14651508
* are included. The following include flags are available for each profile:

0 commit comments

Comments
 (0)