diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/Color.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/Color.java new file mode 100644 index 00000000000..38421745a68 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/Color.java @@ -0,0 +1,32 @@ +package org.opentripplanner.apis.vectortiles; + +/** + * Debug layer colors for drawing shapes on top of the map. + */ +public enum Color { + MAGENTA("#f21d52"), + LIGHT_MAGENTA("#f783a0"), + BRIGHT_GREEN("#22DD9E"), + DARK_GREEN("#136b04"), + TEAL("#277eb5"), + TURQUOISE("#1cafad"), + RED("#fc0f2a"), + PURPLE("#BC55F2"), + BLACK("#140d0e"), + LIGHT_RED("#ff6b6b"), + DARK_RED("#cc0000"), + ORANGE("#ffa500"), + DARK_ORANGE("#ff8c00"), + LIGHT_BLUE("#4a9eff"), + DARK_BLUE("#0066cc"); + + private final String hex; + + Color(String hex) { + this.hex = hex; + } + + public String hex() { + return hex; + } +} diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index 86e0004c141..695343df2be 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -1,5 +1,32 @@ package org.opentripplanner.apis.vectortiles; +import static org.opentripplanner.apis.vectortiles.Color.BLACK; +import static org.opentripplanner.apis.vectortiles.Color.BRIGHT_GREEN; +import static org.opentripplanner.apis.vectortiles.Color.DARK_BLUE; +import static org.opentripplanner.apis.vectortiles.Color.DARK_GREEN; +import static org.opentripplanner.apis.vectortiles.Color.DARK_ORANGE; +import static org.opentripplanner.apis.vectortiles.Color.DARK_RED; +import static org.opentripplanner.apis.vectortiles.Color.LIGHT_BLUE; +import static org.opentripplanner.apis.vectortiles.Color.LIGHT_MAGENTA; +import static org.opentripplanner.apis.vectortiles.Color.LIGHT_RED; +import static org.opentripplanner.apis.vectortiles.Color.MAGENTA; +import static org.opentripplanner.apis.vectortiles.Color.ORANGE; +import static org.opentripplanner.apis.vectortiles.Color.PURPLE; +import static org.opentripplanner.apis.vectortiles.Color.RED; +import static org.opentripplanner.apis.vectortiles.Color.TEAL; +import static org.opentripplanner.apis.vectortiles.Color.TURQUOISE; +import static org.opentripplanner.apis.vectortiles.Group.BICYCLE_SAFETY; +import static org.opentripplanner.apis.vectortiles.Group.EDGES; +import static org.opentripplanner.apis.vectortiles.Group.ELEVATION; +import static org.opentripplanner.apis.vectortiles.Group.NO_THRU_TRAFFIC; +import static org.opentripplanner.apis.vectortiles.Group.PERMISSIONS; +import static org.opentripplanner.apis.vectortiles.Group.RENTAL; +import static org.opentripplanner.apis.vectortiles.Group.STOPS; +import static org.opentripplanner.apis.vectortiles.Group.TRANSFERS; +import static org.opentripplanner.apis.vectortiles.Group.VERTICAL_TRANSPORTATION; +import static org.opentripplanner.apis.vectortiles.Group.VERTICES; +import static org.opentripplanner.apis.vectortiles.Group.WALK_SAFETY; +import static org.opentripplanner.apis.vectortiles.Group.WHEELCHAIR; import static org.opentripplanner.inspector.vector.edge.EdgePropertyMapper.streetPermissionAsString; import static org.opentripplanner.inspector.vector.geofencing.GeofencingZonesPropertyMapper.GEOFENCING_ZONE_TYPE; import static org.opentripplanner.inspector.vector.geofencing.GeofencingZonesPropertyMapper.GEOFENCING_ZONE_TYPE_BUSINESS_AREA; @@ -68,21 +95,6 @@ public class DebugStyleSpec { OSM_BACKGROUND, POSITRON_BACKGROUND ); - private static final String MAGENTA = "#f21d52"; - private static final String LIGHT_MAGENTA = "#f783a0"; - private static final String BRIGHT_GREEN = "#22DD9E"; - private static final String DARK_GREEN = "#136b04"; - private static final String TEAL = "#277eb5"; - private static final String TURQUOISE = "#1cafad"; - private static final String RED = "#fc0f2a"; - private static final String PURPLE = "#BC55F2"; - private static final String BLACK = "#140d0e"; - private static final String LIGHT_RED = "#ff6b6b"; - private static final String DARK_RED = "#cc0000"; - private static final String ORANGE = "#ffa500"; - private static final String DARK_ORANGE = "#ff8c00"; - private static final String LIGHT_BLUE = "#4a9eff"; - private static final String DARK_BLUE = "#0066cc"; private static final int MAX_ZOOM = 23; private static final ZoomDependentNumber LARGE_CIRCLE_LINE_WIDTH = new ZoomDependentNumber( @@ -120,23 +132,12 @@ public class DebugStyleSpec { TemporaryPartialStreetEdge.class, TemporaryFreeEdge.class, }; - private static final String EDGES_GROUP = "Edges"; - private static final String ELEVATION_GROUP = "Elevation"; - private static final String WALK_SAFETY_GROUP = "Walk safety"; - private static final String BICYCLE_SAFETY_GROUP = "Bicycle safety"; - private static final String STOPS_GROUP = "Stops"; - private static final String VERTICES_GROUP = "Vertices"; - private static final String RENTAL_GROUP = "Rental"; - private static final String PERMISSIONS_GROUP = "Permissions"; - private static final String NO_THRU_TRAFFIC_GROUP = "No-thru traffic"; - private static final String VERTICAL_TRANSPORTATION_GROUP = "Vertical transportation"; private static final StreetTraversalPermission[] STREET_MODES = new StreetTraversalPermission[] { StreetTraversalPermission.PEDESTRIAN, StreetTraversalPermission.BICYCLE, StreetTraversalPermission.CAR, }; - private static final String WHEELCHAIR_GROUP = "Wheelchair accessibility"; static StyleSpec build( VectorSourceLayer regularStops, @@ -146,6 +147,7 @@ static StyleSpec build( VectorSourceLayer vertices, VectorSourceLayer geofencingZones, VectorSourceLayer rental, + VectorSourceLayer transfers, List extraLayers ) { List vectorSources = Stream.of( @@ -153,7 +155,8 @@ static StyleSpec build( edges, vertices, geofencingZones, - rental + rental, + transfers ) .map(VectorSourceLayer::vectorSource) .map(TileSource.class::cast) @@ -177,6 +180,7 @@ static StyleSpec build( allSources, ListUtils.combine( backgroundLayers(extraRasterSources), + transfers(transfers), rental(rental, geofencingZones), wheelchair(edges), noThruTraffic(edges), @@ -192,6 +196,20 @@ static StyleSpec build( ); } + private static List transfers(VectorSourceLayer transfers) { + return List.of( + StyleBuilder.ofId("flex-transfers") + .group(TRANSFERS) + .typeLine() + .vectorSourceLayer(transfers) + .lineColor(TEAL) + .lineWidth(LINE_WIDTH) + .minZoom(6) + .maxZoom(MAX_ZOOM) + .intiallyHidden() + ); + } + private static List backgroundLayers(List extraLayers) { return ListUtils.combine(BACKGROUND_LAYERS, extraLayers) .stream() @@ -216,7 +234,7 @@ private static List stops( ) { return List.of( StyleBuilder.ofId("area-stop") - .group(STOPS_GROUP) + .group(STOPS) .typeFill() .vectorSourceLayer(areaStops) .fillColor(BRIGHT_GREEN) @@ -226,7 +244,7 @@ private static List stops( .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("group-stop") - .group(STOPS_GROUP) + .group(STOPS) .typeFill() .vectorSourceLayer(groupStops) .fillColor(BRIGHT_GREEN) @@ -236,7 +254,7 @@ private static List stops( .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("regular-stop") - .group(STOPS_GROUP) + .group(STOPS) .typeCircle() .vectorSourceLayer(regularStops) .circleStroke(BLACK, LARGE_CIRCLE_LINE_WIDTH) @@ -250,7 +268,7 @@ private static List stops( private static List vertices(VectorSourceLayer vertices) { return List.of( StyleBuilder.ofId("vertex") - .group(VERTICES_GROUP) + .group(VERTICES) .typeCircle() .vectorSourceLayer(vertices) .circleStroke(BLACK, CIRCLE_STROKE) @@ -262,7 +280,7 @@ private static List vertices(VectorSourceLayer vertices) { .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("parking-vertex") - .group(VERTICES_GROUP) + .group(VERTICES) .typeCircle() .vectorSourceLayer(vertices) .vertexFilter(VehicleParkingEntranceVertex.class) @@ -273,7 +291,7 @@ private static List vertices(VectorSourceLayer vertices) { .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("barrier-vertex") - .group(VERTICES_GROUP) + .group(VERTICES) .typeCircle() .vectorSourceLayer(vertices) .vertexFilter(BarrierVertex.class) @@ -284,7 +302,7 @@ private static List vertices(VectorSourceLayer vertices) { .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("barrier-passthrough-vertex") - .group(VERTICES_GROUP) + .group(VERTICES) .typeCircle() .vectorSourceLayer(vertices) .vertexFilter(BarrierPassThroughVertex.class) @@ -300,7 +318,7 @@ private static List vertices(VectorSourceLayer vertices) { private static List elevators(VectorSourceLayer edges, VectorSourceLayer vertices) { return List.of( StyleBuilder.ofId("elevator-hop-edge") - .group(VERTICAL_TRANSPORTATION_GROUP) + .group(VERTICAL_TRANSPORTATION) .typeLine() .vectorSourceLayer(edges) .edgeFilter(ElevatorHopEdge.class) @@ -311,7 +329,7 @@ private static List elevators(VectorSourceLayer edges, VectorSourc .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("elevator-board-edge") - .group(VERTICAL_TRANSPORTATION_GROUP) + .group(VERTICAL_TRANSPORTATION) .typeLine() .vectorSourceLayer(edges) .edgeFilter(ElevatorBoardEdge.class) @@ -322,7 +340,7 @@ private static List elevators(VectorSourceLayer edges, VectorSourc .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("elevator-alight-edge") - .group(VERTICAL_TRANSPORTATION_GROUP) + .group(VERTICAL_TRANSPORTATION) .typeLine() .vectorSourceLayer(edges) .edgeFilter(ElevatorAlightEdge.class) @@ -333,7 +351,7 @@ private static List elevators(VectorSourceLayer edges, VectorSourc .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("elevator-hop-vertex") - .group(VERTICAL_TRANSPORTATION_GROUP) + .group(VERTICAL_TRANSPORTATION) .typeCircle() .vectorSourceLayer(vertices) .vertexFilter(ElevatorHopVertex.class) @@ -346,7 +364,7 @@ private static List elevators(VectorSourceLayer edges, VectorSourc .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("osm-elevator-vertex") - .group(VERTICAL_TRANSPORTATION_GROUP) + .group(VERTICAL_TRANSPORTATION) .typeCircle() .vectorSourceLayer(vertices) .vertexFilter(OsmElevatorVertex.class) @@ -359,7 +377,7 @@ private static List elevators(VectorSourceLayer edges, VectorSourc .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("escalator-edge") - .group(VERTICAL_TRANSPORTATION_GROUP) + .group(VERTICAL_TRANSPORTATION) .typeLine() .vectorSourceLayer(edges) .edgeFilter(EscalatorEdge.class) @@ -370,7 +388,7 @@ private static List elevators(VectorSourceLayer edges, VectorSourc .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("stairs-edge") - .group(VERTICAL_TRANSPORTATION_GROUP) + .group(VERTICAL_TRANSPORTATION) .typeLine() .vectorSourceLayer(edges) .booleanFilter("isStairs", true) @@ -389,7 +407,7 @@ private static List rental( ) { return List.of( StyleBuilder.ofId("rental-vehicle") - .group(RENTAL_GROUP) + .group(RENTAL) .typeCircle() .vectorSourceLayer(rentalLayer) .classFilter(VehicleRentalVehicle.class) @@ -400,7 +418,7 @@ private static List rental( .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("rental-station") - .group(RENTAL_GROUP) + .group(RENTAL) .typeCircle() .vectorSourceLayer(rentalLayer) .classFilter(VehicleRentalStation.class) @@ -411,7 +429,7 @@ private static List rental( .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("geofencing-zones-no-drop-off") - .group(RENTAL_GROUP) + .group(RENTAL) .typeFill() .vectorSourceLayer(geofencingZones) .filterValueInProperty(GEOFENCING_ZONE_TYPE, GEOFENCING_ZONE_TYPE_NO_DROP_OFF) @@ -422,7 +440,7 @@ private static List rental( .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("geofencing-zones-no-traversal") - .group(RENTAL_GROUP) + .group(RENTAL) .typeFill() .vectorSourceLayer(geofencingZones) .filterValueInProperty(GEOFENCING_ZONE_TYPE, GEOFENCING_ZONE_TYPE_NO_TRAVERSAL) @@ -433,7 +451,7 @@ private static List rental( .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("geofencing-zones-business-area") - .group(RENTAL_GROUP) + .group(RENTAL) .typeFill() .vectorSourceLayer(geofencingZones) .filterValueInProperty(GEOFENCING_ZONE_TYPE, GEOFENCING_ZONE_TYPE_BUSINESS_AREA) @@ -449,7 +467,7 @@ private static List rental( private static List edges(VectorSourceLayer edges) { return List.of( StyleBuilder.ofId("area-edge") - .group(EDGES_GROUP) + .group(EDGES) .typeLine() .vectorSourceLayer(edges) .edgeFilter(AreaEdge.class) @@ -461,7 +479,7 @@ private static List edges(VectorSourceLayer edges) { .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("edge") - .group(EDGES_GROUP) + .group(EDGES) .typeLine() .vectorSourceLayer(edges) .lineColor(MAGENTA) @@ -472,7 +490,7 @@ private static List edges(VectorSourceLayer edges) { .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("edge-name") - .group(EDGES_GROUP) + .group(EDGES) .typeSymbol() .lineText("name") .vectorSourceLayer(edges) @@ -481,7 +499,7 @@ private static List edges(VectorSourceLayer edges) { .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("link") - .group(EDGES_GROUP) + .group(EDGES) .typeLine() .vectorSourceLayer(edges) .lineColor(BRIGHT_GREEN) @@ -504,7 +522,7 @@ private static List edges(VectorSourceLayer edges) { private static List elevation(VectorSourceLayer edges, VectorSourceLayer vertices) { return List.of( StyleBuilder.ofId("maximum-slope") - .group(ELEVATION_GROUP) + .group(ELEVATION) .typeLine() .vectorSourceLayer(edges) // Slope can be higher than this in theory but distinction between high values is not needed @@ -516,7 +534,7 @@ private static List elevation(VectorSourceLayer edges, VectorSourc .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder.ofId("vertex-elevation") - .group(ELEVATION_GROUP) + .group(ELEVATION) .typeSymbol() .symbolText("elevation") .vectorSourceLayer(vertices) @@ -529,7 +547,7 @@ private static List elevation(VectorSourceLayer edges, VectorSourc private static List bicycleSafety(VectorSourceLayer edges) { return List.of( StyleBuilder.ofId("bicycle-safety") - .group(BICYCLE_SAFETY_GROUP) + .group(BICYCLE_SAFETY) .typeLine() .vectorSourceLayer(edges) .log2LineColorFromProperty("bicycleSafetyFactor", 80) @@ -541,7 +559,7 @@ private static List bicycleSafety(VectorSourceLayer edges) { .intiallyHidden(), StyleBuilder.ofId("bicycle-safety-text") .vectorSourceLayer(edges) - .group(BICYCLE_SAFETY_GROUP) + .group(BICYCLE_SAFETY) .typeSymbol() .lineText("bicycleSafetyFactor") .textOffset(1) @@ -555,7 +573,7 @@ private static List bicycleSafety(VectorSourceLayer edges) { private static List walkSafety(VectorSourceLayer edges) { return List.of( StyleBuilder.ofId("walk-safety") - .group(WALK_SAFETY_GROUP) + .group(WALK_SAFETY) .typeLine() .vectorSourceLayer(edges) .log2LineColorFromProperty("walkSafetyFactor", 80) @@ -567,7 +585,7 @@ private static List walkSafety(VectorSourceLayer edges) { .intiallyHidden(), StyleBuilder.ofId("walk-safety-text") .vectorSourceLayer(edges) - .group(WALK_SAFETY_GROUP) + .group(WALK_SAFETY) .typeSymbol() .lineText("walkSafetyFactor") .textOffset(1) @@ -583,7 +601,7 @@ private static List traversalPermissions(VectorSourceLayer edges) .map(streetTraversalPermission -> StyleBuilder.ofId("permission " + streetTraversalPermission) .vectorSourceLayer(edges) - .group(PERMISSIONS_GROUP) + .group(PERMISSIONS) .typeLine() .filterValueInProperty( "permission", @@ -602,7 +620,7 @@ private static List traversalPermissions(VectorSourceLayer edges) var textStyle = StyleBuilder.ofId("permission-text") .vectorSourceLayer(edges) - .group(PERMISSIONS_GROUP) + .group(PERMISSIONS) .typeSymbol() .lineText("permission") .textOffset(1) @@ -619,7 +637,7 @@ private static List noThruTraffic(VectorSourceLayer edges) { .map(streetTraversalPermission -> StyleBuilder.ofId("no-thru-traffic " + streetTraversalPermission) .vectorSourceLayer(edges) - .group(NO_THRU_TRAFFIC_GROUP) + .group(NO_THRU_TRAFFIC) .typeLine() .filterValueInProperty( "noThruTraffic", @@ -638,7 +656,7 @@ private static List noThruTraffic(VectorSourceLayer edges) { var textStyle = StyleBuilder.ofId("no-thru-traffic-text") .vectorSourceLayer(edges) - .group(NO_THRU_TRAFFIC_GROUP) + .group(NO_THRU_TRAFFIC) .typeSymbol() .lineText("noThruTraffic") .textOffset(1) @@ -660,7 +678,7 @@ private static List wheelchair(VectorSourceLayer edges) { return List.of( StyleBuilder.ofId("wheelchair-accessible") .vectorSourceLayer(edges) - .group(WHEELCHAIR_GROUP) + .group(WHEELCHAIR) .typeLine() .lineColor(DARK_GREEN) .booleanFilter("wheelchairAccessible", true) @@ -671,7 +689,7 @@ private static List wheelchair(VectorSourceLayer edges) { .intiallyHidden(), StyleBuilder.ofId("wheelchair-inaccessible") .vectorSourceLayer(edges) - .group(WHEELCHAIR_GROUP) + .group(WHEELCHAIR) .typeLine() .lineColor(RED) .booleanFilter("wheelchairAccessible", false) @@ -685,7 +703,7 @@ private static List wheelchair(VectorSourceLayer edges) { private static String permissionColor(StreetTraversalPermission p) { return switch (p) { - case NONE -> BLACK; + case NONE -> BLACK.hex(); case PEDESTRIAN -> "#2ba812"; case BICYCLE, PEDESTRIAN_AND_BICYCLE -> "#10d3b6"; case CAR -> "#f92e13"; diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugVectorTilesResource.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugVectorTilesResource.java index 92bf3c51e22..9d39f319f71 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugVectorTilesResource.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugVectorTilesResource.java @@ -6,6 +6,7 @@ import static org.opentripplanner.apis.vectortiles.model.LayerType.GroupStop; import static org.opentripplanner.apis.vectortiles.model.LayerType.RegularStop; import static org.opentripplanner.apis.vectortiles.model.LayerType.Rental; +import static org.opentripplanner.apis.vectortiles.model.LayerType.Transfers; import static org.opentripplanner.apis.vectortiles.model.LayerType.Vertex; import static org.opentripplanner.framework.io.HttpUtils.APPLICATION_X_PROTOBUF; import static org.opentripplanner.inspector.vector.LayerParameters.MAX_ZOOM; @@ -41,6 +42,7 @@ import org.opentripplanner.inspector.vector.rental.RentalLayerBuilder; import org.opentripplanner.inspector.vector.stop.GroupStopLayerBuilder; import org.opentripplanner.inspector.vector.stop.StopLayerBuilder; +import org.opentripplanner.inspector.vector.transfers.TransfersLayerBuilder; import org.opentripplanner.inspector.vector.vertex.VertexLayerBuilder; import org.opentripplanner.model.FeedInfo; import org.opentripplanner.standalone.api.OtpServerRequestContext; @@ -62,6 +64,7 @@ public class DebugVectorTilesResource { private static final LayerParams EDGES = new LayerParams("edges", Edge); private static final LayerParams VERTICES = new LayerParams("vertices", Vertex); private static final LayerParams RENTAL = new LayerParams("rental", Rental); + private static final LayerParams TRANSFERS = new LayerParams("transfers", Transfers); private static final List> DEBUG_LAYERS = List.of( REGULAR_STOPS, AREA_STOPS, @@ -69,7 +72,8 @@ public class DebugVectorTilesResource { GEOFENCING_ZONES, EDGES, VERTICES, - RENTAL + RENTAL, + TRANSFERS ); public static final String PATH = "/otp/debug/vectortiles/"; @@ -135,6 +139,7 @@ public StyleSpec getTileJson(@Context UriInfo uri, @Context HttpHeaders headers) tileJsonUrl(base, List.of(GEOFENCING_ZONES)) ); var rentalSource = new VectorSource("rental", tileJsonUrl(base, List.of(RENTAL))); + var transferSource = new VectorSource("transfers", tileJsonUrl(base, List.of(TRANSFERS))); return DebugStyleSpec.build( REGULAR_STOPS.toVectorSourceLayer(stopsSource), @@ -144,6 +149,7 @@ public StyleSpec getTileJson(@Context UriInfo uri, @Context HttpHeaders headers) VERTICES.toVectorSourceLayer(streetSource), GEOFENCING_ZONES.toVectorSourceLayer(geofencingSource), RENTAL.toVectorSourceLayer(rentalSource), + TRANSFERS.toVectorSourceLayer(transferSource), serverContext.debugUiConfig().additionalBackgroundLayers() ); } @@ -195,6 +201,11 @@ private static LayerBuilder createLayerBuilder( ); case Vertex -> new VertexLayerBuilder(context.graph(), layerParameters); case Rental -> new RentalLayerBuilder(context.vehicleRentalService(), layerParameters); + case Transfers -> new TransfersLayerBuilder( + context.transitService(), + context.transferService(), + layerParameters + ); }; } } diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/Group.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/Group.java new file mode 100644 index 00000000000..1041c1fe530 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/Group.java @@ -0,0 +1,29 @@ +package org.opentripplanner.apis.vectortiles; + +/** + * Enum for debug layer groups. In the debug UI they are shown on the layer selection menu. + */ +public enum Group { + EDGES("Edges"), + ELEVATION("Elevation"), + WALK_SAFETY("Walk safety"), + BICYCLE_SAFETY("Bicycle safety"), + STOPS("Stops"), + VERTICES("Vertices"), + RENTAL("Rental"), + PERMISSIONS("Permissions"), + NO_THRU_TRAFFIC("No-thru traffic"), + VERTICAL_TRANSPORTATION("Vertical transportation"), + WHEELCHAIR("Wheelchair accessibility"), + TRANSFERS("Transfers"); + + private final String label; + + Group(String label) { + this.label = label; + } + + public String label() { + return label; + } +} diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/model/LayerType.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/model/LayerType.java index b85401ff776..ab1357bc3c6 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/model/LayerType.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/model/LayerType.java @@ -8,4 +8,5 @@ public enum LayerType { Edge, Vertex, Rental, + Transfers, } diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java index 739dff68d5e..51f394ff109 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java @@ -12,6 +12,8 @@ import java.util.Map; import java.util.Objects; import java.util.stream.Stream; +import org.opentripplanner.apis.vectortiles.Color; +import org.opentripplanner.apis.vectortiles.Group; import org.opentripplanner.apis.vectortiles.model.ZoomDependentNumber.ZoomStop; import org.opentripplanner.framework.json.ObjectMappers; import org.opentripplanner.street.model.edge.Edge; @@ -117,8 +119,8 @@ private StyleBuilder type(LayerType type) { * Puts the layer into an arbitrarily defined group in the layer selector. This allows you * to switch the entire group on and off. */ - public StyleBuilder group(String group) { - metadata.put("group", group); + public StyleBuilder group(Group group) { + metadata.put("group", group.label()); return this; } @@ -159,13 +161,17 @@ public StyleBuilder textOffset(float offset) { return this; } + public StyleBuilder circleColor(Color color) { + return circleColor(color.hex()); + } + public StyleBuilder circleColor(String color) { paint.put("circle-color", validateColor(color)); return this; } - public StyleBuilder circleStroke(String color, ZoomDependentNumber width) { - paint.put("circle-stroke-color", validateColor(color)); + public StyleBuilder circleStroke(Color color, ZoomDependentNumber width) { + paint.put("circle-stroke-color", validateColor(color.hex())); paint.put("circle-stroke-width", width.toJson()); return this; } @@ -181,8 +187,8 @@ public StyleBuilder lineCap(String lineCap) { return this; } - public StyleBuilder lineColor(String color) { - paint.put("line-color", validateColor(color)); + public StyleBuilder lineColor(Color color) { + paint.put("line-color", validateColor(color.hex())); return this; } @@ -229,14 +235,14 @@ public StyleBuilder log2LineColorFromProperty(String propertyName, double logMul public StyleBuilder lineColorMatch( String propertyName, Collection values, - String defaultValue + Color defaultValue ) { paint.put( "line-color", ListUtils.combine( List.of("match", List.of("get", propertyName)), (Collection) values, - List.of(defaultValue) + List.of(defaultValue.hex()) ) ); return this; @@ -252,8 +258,8 @@ public StyleBuilder lineOffset(ZoomDependentNumber zoomStops) { return this; } - public StyleBuilder fillColor(String color) { - paint.put("fill-color", validateColor(color)); + public StyleBuilder fillColor(Color color) { + paint.put("fill-color", validateColor(color.hex())); return this; } @@ -262,8 +268,8 @@ public StyleBuilder fillOpacity(float opacity) { return this; } - public StyleBuilder fillOutlineColor(String color) { - paint.put("fill-outline-color", validateColor(color)); + public StyleBuilder fillOutlineColor(Color color) { + paint.put("fill-outline-color", validateColor(color.hex())); return this; } diff --git a/application/src/main/java/org/opentripplanner/inspector/vector/transfers/PathTransferPropertyMapper.java b/application/src/main/java/org/opentripplanner/inspector/vector/transfers/PathTransferPropertyMapper.java new file mode 100644 index 00000000000..e8c27b83033 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/inspector/vector/transfers/PathTransferPropertyMapper.java @@ -0,0 +1,23 @@ +package org.opentripplanner.inspector.vector.transfers; + +import static org.opentripplanner.inspector.vector.KeyValue.kv; + +import java.util.Collection; +import java.util.List; +import org.opentripplanner.apis.support.mapping.PropertyMapper; +import org.opentripplanner.inspector.vector.KeyValue; +import org.opentripplanner.transfer.regular.model.PathTransfer; + +public class PathTransferPropertyMapper extends PropertyMapper { + + @Override + protected Collection map(PathTransfer input) { + return List.of( + kv("class", input.getClass().getSimpleName()), + kv("name", "Flex transfer %s → %s".formatted(input.from.getId(), input.to.getId())), + kv("from", input.from.getId()), + kv("to", input.to.getId()), + kv("meters", input.getDistanceMeters()) + ); + } +} diff --git a/application/src/main/java/org/opentripplanner/inspector/vector/transfers/TransfersLayerBuilder.java b/application/src/main/java/org/opentripplanner/inspector/vector/transfers/TransfersLayerBuilder.java new file mode 100644 index 00000000000..edef4487b27 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/inspector/vector/transfers/TransfersLayerBuilder.java @@ -0,0 +1,45 @@ +package org.opentripplanner.inspector.vector.transfers; + +import java.util.List; +import org.locationtech.jts.geom.Envelope; +import org.locationtech.jts.geom.Geometry; +import org.opentripplanner.apis.vectortiles.model.LayerType; +import org.opentripplanner.inspector.vector.LayerBuilder; +import org.opentripplanner.inspector.vector.LayerParameters; +import org.opentripplanner.transfer.regular.RegularTransferService; +import org.opentripplanner.transfer.regular.model.PathTransfer; +import org.opentripplanner.transit.service.TransitService; + +public class TransfersLayerBuilder extends LayerBuilder { + + private final TransitService transitService; + private final RegularTransferService transferService; + + public TransfersLayerBuilder( + TransitService siteRepo, + RegularTransferService transferService, + LayerParameters layerParameters + ) { + super( + new PathTransferPropertyMapper(), + layerParameters.name(), + layerParameters.expansionFactor() + ); + this.transitService = siteRepo; + this.transferService = transferService; + } + + @Override + protected List getGeometries(Envelope envelope) { + return transitService + .findAreaStops(envelope) + .stream() + .flatMap(stop -> transferService.findWalkTransfersFromStop(stop).stream()) + .map(p -> { + var g = (Geometry) p.getGeometry(); + g.setUserData(p); + return g; + }) + .toList(); + } +} diff --git a/application/src/main/java/org/opentripplanner/transfer/regular/model/PathTransfer.java b/application/src/main/java/org/opentripplanner/transfer/regular/model/PathTransfer.java index 0d339a207e2..b4836272d3d 100644 --- a/application/src/main/java/org/opentripplanner/transfer/regular/model/PathTransfer.java +++ b/application/src/main/java/org/opentripplanner/transfer/regular/model/PathTransfer.java @@ -61,10 +61,6 @@ public PathTransfer( this.modes = modes; } - public String getName() { - return from + " => " + to; - } - public double getDistanceMeters() { return distanceMeters; } diff --git a/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java b/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java index b763479779b..d9bb71bcccf 100644 --- a/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java +++ b/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java @@ -30,6 +30,7 @@ void spec() { var vertices = new VectorSourceLayer(vectorSource, "vertices"); var geofencingZones = new VectorSourceLayer(vectorSource, "geofencingZones"); var rental = new VectorSourceLayer(vectorSource, "rental"); + var transfers = new VectorSourceLayer(vectorSource, "transfers"); var spec = DebugStyleSpec.build( regularStops, areaStops, @@ -38,6 +39,7 @@ void spec() { vertices, geofencingZones, rental, + transfers, List.of() ); diff --git a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json index dd02cb18921..a79196f383c 100644 --- a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json +++ b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json @@ -51,6 +51,37 @@ "name" : "Positron" } }, + { + "id" : "flex-transfers", + "type" : "line", + "source" : "vectorSource", + "source-layer" : "transfers", + "minzoom" : 6, + "maxzoom" : 23, + "paint" : { + "line-color" : "#277eb5", + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ] + }, + "layout" : { + "line-cap" : "round", + "visibility" : "none" + }, + "metadata" : { + "group" : "Transfers" + } + }, { "id" : "rental-vehicle", "type" : "circle",