Skip to content

Commit

Permalink
Merge pull request #6146 from realCity/feature/layer-groups
Browse files Browse the repository at this point in the history
vector tile: add no-thru traffic restrictions layer
  • Loading branch information
flaktack authored Nov 12, 2024
2 parents 14333d1 + 0b6fcac commit 3d5d504
Show file tree
Hide file tree
Showing 6 changed files with 627 additions and 267 deletions.
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)
.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

0 comments on commit 3d5d504

Please sign in to comment.