Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vector tile: add no-thru traffic restrictions layer #6146

Merged
merged 6 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.opentripplanner.apis.vectortiles;

import static org.opentripplanner.inspector.vector.edge.EdgePropertyMapper.streetPermissionAsString;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -30,8 +32,8 @@
import org.opentripplanner.utils.collection.ListUtils;

/**
* A Mapbox/Mapblibre style specification for rendering debug information about transit and
* street data.
* A Mapbox/Mapblibre style specification for rendering debug information about transit and street
* data.
*/
public class DebugStyleSpec {

Expand All @@ -49,11 +51,15 @@ public class DebugStyleSpec {
private static final String BLACK = "#140d0e";

private static final int MAX_ZOOM = 23;
private static final int LINE_DETAIL_ZOOM = 13;
private static final ZoomDependentNumber LINE_OFFSET = new ZoomDependentNumber(
List.of(new ZoomStop(13, 0.3f), new ZoomStop(MAX_ZOOM, 6))
List.of(new ZoomStop(LINE_DETAIL_ZOOM, 0.4f), new ZoomStop(MAX_ZOOM, 7))
);
private static final ZoomDependentNumber LINE_WIDTH = new ZoomDependentNumber(
List.of(new ZoomStop(13, 0.2f), new ZoomStop(MAX_ZOOM, 8))
List.of(new ZoomStop(LINE_DETAIL_ZOOM, 0.2f), new ZoomStop(MAX_ZOOM, 8))
);
private static final ZoomDependentNumber LINE_HALF_WIDTH = new ZoomDependentNumber(
List.of(new ZoomStop(LINE_DETAIL_ZOOM, 0.1f), new ZoomStop(MAX_ZOOM, 6))
);
private static final ZoomDependentNumber CIRCLE_STROKE = new ZoomDependentNumber(
List.of(new ZoomStop(15, 0.2f), new ZoomStop(MAX_ZOOM, 3))
Expand All @@ -70,7 +76,14 @@ public class DebugStyleSpec {
private static final String EDGES_GROUP = "Edges";
private static final String STOPS_GROUP = "Stops";
private static final String VERTICES_GROUP = "Vertices";
private static final String TRAVERSAL_PERMISSIONS_GROUP = "Traversal permissions";
private static final String PERMISSIONS_GROUP = "Permissions";
private static final String NO_THRU_TRAFFIC_GROUP = "No-thru traffic";

private static final StreetTraversalPermission[] streetModes = new StreetTraversalPermission[] {
StreetTraversalPermission.PEDESTRIAN,
StreetTraversalPermission.BICYCLE,
StreetTraversalPermission.CAR,
};

static StyleSpec build(
VectorSourceLayer regularStops,
Expand All @@ -90,8 +103,9 @@ static StyleSpec build(
allSources,
ListUtils.combine(
List.of(StyleBuilder.ofId("background").typeRaster().source(BACKGROUND_SOURCE).minZoom(0)),
traversalPermissions(edges),
edges(edges),
traversalPermissions(edges),
noThruTraffic(edges),
vertices(vertices),
stops(regularStops, areaStops, groupStops)
)
Expand Down Expand Up @@ -183,7 +197,7 @@ private static List<StyleBuilder> edges(VectorSourceLayer edges) {
.vectorSourceLayer(edges)
.lineColor(MAGENTA)
.edgeFilter(EDGES_TO_DISPLAY)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why we remove this filter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The style changes have been reverted.

Since only the edge layer was interactive, my thought was to have an indicative background layer on which any edge could be selected.

That has been replaced with an update to MapControl/LayerControl so that the list of dynamic layers is updated based on the selected layers.

.lineWidth(LINE_WIDTH)
.lineWidth(LINE_HALF_WIDTH)
.lineOffset(LINE_OFFSET)
.minZoom(6)
.maxZoom(MAX_ZOOM)
Expand Down Expand Up @@ -222,39 +236,92 @@ private static List<StyleBuilder> edges(VectorSourceLayer edges) {

private static List<StyleBuilder> traversalPermissions(VectorSourceLayer edges) {
var permissionStyles = Arrays
.stream(StreetTraversalPermission.values())
.map(p ->
.stream(streetModes)
.map(streetTraversalPermission ->
StyleBuilder
.ofId(p.name())
.ofId("permission " + streetTraversalPermission)
.vectorSourceLayer(edges)
.group(TRAVERSAL_PERMISSIONS_GROUP)
.group(PERMISSIONS_GROUP)
.typeLine()
.lineColor(permissionColor(p))
.permissionsFilter(p)
.filterValueInProperty(
"permission",
streetTraversalPermission.name(),
StreetTraversalPermission.ALL.name()
)
.lineCap("butt")
.lineColorMatch("permission", permissionColors(), BLACK)
.lineWidth(LINE_WIDTH)
.lineOffset(LINE_OFFSET)
.minZoom(6)
.minZoom(LINE_DETAIL_ZOOM)
.maxZoom(MAX_ZOOM)
.intiallyHidden()
)
.toList();

var textStyle = StyleBuilder
.ofId("permission-text")
.vectorSourceLayer(edges)
.group(TRAVERSAL_PERMISSIONS_GROUP)
.group(PERMISSIONS_GROUP)
.typeSymbol()
.lineText("permission")
.textOffset(1)
.edgeFilter(EDGES_TO_DISPLAY)
.minZoom(17)
.maxZoom(MAX_ZOOM)
.intiallyHidden();

return ListUtils.combine(permissionStyles, List.of(textStyle));
}

private static List<StyleBuilder> noThruTraffic(VectorSourceLayer edges) {
var noThruTrafficStyles = Arrays
.stream(streetModes)
.map(streetTraversalPermission ->
StyleBuilder
.ofId("no-thru-traffic " + streetTraversalPermission)
.vectorSourceLayer(edges)
.group(NO_THRU_TRAFFIC_GROUP)
.typeLine()
.filterValueInProperty(
"noThruTraffic",
streetTraversalPermission.name(),
StreetTraversalPermission.ALL.name()
)
.lineCap("butt")
.lineColorMatch("noThruTraffic", permissionColors(), BLACK)
.lineWidth(LINE_WIDTH)
.lineOffset(LINE_OFFSET)
.minZoom(LINE_DETAIL_ZOOM)
.maxZoom(MAX_ZOOM)
.intiallyHidden()
)
.toList();

var textStyle = StyleBuilder
.ofId("no-thru-traffic-text")
.vectorSourceLayer(edges)
.group(NO_THRU_TRAFFIC_GROUP)
.typeSymbol()
.lineText("noThruTraffic")
.textOffset(1)
.edgeFilter(EDGES_TO_DISPLAY)
.minZoom(17)
.maxZoom(MAX_ZOOM)
.intiallyHidden();

return ListUtils.combine(noThruTrafficStyles, List.of(textStyle));
}

private static List<String> permissionColors() {
return Arrays
.stream(StreetTraversalPermission.values())
.flatMap(p -> Stream.of(streetPermissionAsString(p), permissionColor(p)))
.toList();
}

private static String permissionColor(StreetTraversalPermission p) {
return switch (p) {
case NONE -> "#000";
case NONE -> BLACK;
case PEDESTRIAN -> "#2ba812";
case BICYCLE, PEDESTRIAN_AND_BICYCLE -> "#10d3b6";
case CAR -> "#f92e13";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;
import org.opentripplanner.apis.vectortiles.model.ZoomDependentNumber.ZoomStop;
import org.opentripplanner.framework.json.ObjectMappers;
import org.opentripplanner.street.model.StreetTraversalPermission;
import org.opentripplanner.street.model.edge.Edge;
import org.opentripplanner.street.model.vertex.Vertex;
import org.opentripplanner.utils.collection.ListUtils;
Expand All @@ -29,7 +30,7 @@ public class StyleBuilder {
private final Map<String, Object> layout = new LinkedHashMap<>();
private final Map<String, Object> metadata = new LinkedHashMap<>();
private final Map<String, Object> line = new LinkedHashMap<>();
private List<String> filter = List.of();
private List<? extends Object> filter = List.of();

public static StyleBuilder ofId(String id) {
return new StyleBuilder(id);
Expand Down Expand Up @@ -167,12 +168,42 @@ public StyleBuilder circleRadius(ZoomDependentNumber radius) {
}

// Line styling
public StyleBuilder lineCap(String lineCap) {
layout.put("line-cap", lineCap);
return this;
}

public StyleBuilder lineColor(String color) {
paint.put("line-color", validateColor(color));
return this;
}

public StyleBuilder lineColorMatch(
String propertyName,
Collection<String> values,
String defaultValue
) {
paint.put(
"line-color",
ListUtils.combine(
List.of("match", List.of("get", propertyName)),
(Collection) values,
List.of(defaultValue)
)
);
return this;
}

public StyleBuilder lineOpacity(float lineOpacity) {
paint.put("line-opacity", lineOpacity);
return this;
}

public StyleBuilder lineDasharray(float... dashArray) {
paint.put("line-dasharray", dashArray);
return this;
}

public StyleBuilder lineWidth(float width) {
paint.put("line-width", width);
return this;
Expand Down Expand Up @@ -219,14 +250,6 @@ public final StyleBuilder edgeFilter(Class<? extends Edge>... classToFilter) {
return filterClasses(classToFilter);
}

/**
* Filter the entities by their "permission" property.
*/
public final StyleBuilder permissionsFilter(StreetTraversalPermission p) {
filter = List.of("==", "permission", p.name());
return this;
}

/**
* Only apply the style to the given vertices.
*/
Expand All @@ -235,6 +258,16 @@ public final StyleBuilder vertexFilter(Class<? extends Vertex>... classToFilter)
return filterClasses(classToFilter);
}

public StyleBuilder filterValueInProperty(String propertyName, String... values) {
var newFilter = new ArrayList<>();
newFilter.add("any");
for (String value : values) {
newFilter.add(List.of("in", value, List.of("string", List.of("get", propertyName))));
}
filter = newFilter;
return this;
}

public JsonNode toJson() {
validate();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.List;
import org.opentripplanner.apis.support.mapping.PropertyMapper;
import org.opentripplanner.inspector.vector.KeyValue;
import org.opentripplanner.street.model.StreetTraversalPermission;
import org.opentripplanner.street.model.edge.Edge;
import org.opentripplanner.street.model.edge.EscalatorEdge;
import org.opentripplanner.street.model.edge.StreetEdge;
Expand All @@ -29,8 +30,9 @@ protected Collection<KeyValue> map(Edge input) {

private static List<KeyValue> mapStreetEdge(StreetEdge se) {
var props = Lists.newArrayList(
kv("permission", se.getPermission().toString()),
kv("bicycleSafetyFactor", roundTo2Decimals(se.getBicycleSafetyFactor()))
kv("permission", streetPermissionAsString(se.getPermission())),
kv("bicycleSafetyFactor", roundTo2Decimals(se.getBicycleSafetyFactor())),
kv("noThruTraffic", noThruTrafficAsString(se))
);
if (se.hasBogusName()) {
props.addFirst(kv("name", "%s (generated)".formatted(se.getName().toString())));
Expand All @@ -39,4 +41,22 @@ private static List<KeyValue> mapStreetEdge(StreetEdge se) {
}
return props;
}

public static String streetPermissionAsString(StreetTraversalPermission permission) {
return permission.name().replace("_AND_", " ");
}

private static String noThruTrafficAsString(StreetEdge se) {
var noThruPermission = StreetTraversalPermission.NONE;
if (se.isWalkNoThruTraffic()) {
noThruPermission = noThruPermission.add(StreetTraversalPermission.PEDESTRIAN);
}
if (se.isBicycleNoThruTraffic()) {
noThruPermission = noThruPermission.add(StreetTraversalPermission.BICYCLE);
}
if (se.isMotorVehicleNoThruTraffic()) {
noThruPermission = noThruPermission.add(StreetTraversalPermission.CAR);
}
return streetPermissionAsString(noThruPermission);
}
}
Loading
Loading