Skip to content

Commit

Permalink
Merge pull request #6229 from ibi-group/wheelchair-debug
Browse files Browse the repository at this point in the history
Fix parsing of wheelchair accessible parking, add wheelchair debug layer
  • Loading branch information
leonardehrenfried authored Nov 12, 2024
2 parents a0bd2b6 + 9812c5b commit 7b4d240
Show file tree
Hide file tree
Showing 10 changed files with 266 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public class DebugStyleSpec {
private static final String MAGENTA = "#f21d52";
private static final String BRIGHT_GREEN = "#22DD9E";
private static final String DARK_GREEN = "#136b04";
private static final String RED = "#fc0f2a";
private static final String PURPLE = "#BC55F2";
private static final String BLACK = "#140d0e";

Expand Down Expand Up @@ -84,6 +85,7 @@ public class DebugStyleSpec {
StreetTraversalPermission.BICYCLE,
StreetTraversalPermission.CAR,
};
private static final String WHEELCHAIR_GROUP = "Wheelchair accessibility";

static StyleSpec build(
VectorSourceLayer regularStops,
Expand All @@ -103,6 +105,7 @@ static StyleSpec build(
allSources,
ListUtils.combine(
List.of(StyleBuilder.ofId("background").typeRaster().source(BACKGROUND_SOURCE).minZoom(0)),
wheelchair(edges),
edges(edges),
traversalPermissions(edges),
noThruTraffic(edges),
Expand Down Expand Up @@ -319,6 +322,35 @@ private static List<String> permissionColors() {
.toList();
}

private static List<StyleBuilder> wheelchair(VectorSourceLayer edges) {
return List.of(
StyleBuilder
.ofId("wheelchair-accessible")
.vectorSourceLayer(edges)
.group(WHEELCHAIR_GROUP)
.typeLine()
.lineColor(DARK_GREEN)
.booleanFilter("wheelchairAccessible", true)
.lineWidth(LINE_WIDTH)
.lineOffset(LINE_OFFSET)
.minZoom(6)
.maxZoom(MAX_ZOOM)
.intiallyHidden(),
StyleBuilder
.ofId("wheelchair-inaccessible")
.vectorSourceLayer(edges)
.group(WHEELCHAIR_GROUP)
.typeLine()
.lineColor(RED)
.booleanFilter("wheelchairAccessible", false)
.lineWidth(LINE_WIDTH)
.lineOffset(LINE_OFFSET)
.minZoom(6)
.maxZoom(MAX_ZOOM)
.intiallyHidden()
);
}

private static String permissionColor(StreetTraversalPermission p) {
return switch (p) {
case NONE -> BLACK;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,14 @@ public final StyleBuilder edgeFilter(Class<? extends Edge>... classToFilter) {
return filterClasses(classToFilter);
}

/**
* Filter the entities by a boolean property.
*/
public final StyleBuilder booleanFilter(String propertyName, boolean value) {
filter = List.of("==", propertyName, value);
return this;
}

/**
* Only apply the style to the given vertices.
*/
Expand Down Expand Up @@ -290,7 +298,7 @@ public JsonNode toJson() {

private StyleBuilder filterClasses(Class... classToFilter) {
var clazzes = Arrays.stream(classToFilter).map(Class::getSimpleName).toList();
filter = ListUtils.combine(List.of("in", "class"), clazzes);
filter = new ArrayList<>(ListUtils.combine(List.of("in", "class"), clazzes));
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ private List<VehicleParking.VehicleParkingEntranceCreator> createArtificialEntra
);
}

private VehicleParking createVehicleParkingObjectFromOsmEntity(
VehicleParking createVehicleParkingObjectFromOsmEntity(
boolean isCarParkAndRide,
Coordinate coordinate,
OsmWithTags entity,
Expand Down Expand Up @@ -421,7 +421,7 @@ private OptionalInt parseCapacity(OsmWithTags element) {
}

private OptionalInt parseCapacity(OsmWithTags element, String capacityTag) {
return element.getTagAsInt(
return element.parseIntOrBoolean(
capacityTag,
v -> issueStore.add(new InvalidVehicleParkingCapacity(element, v))
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ private static List<KeyValue> mapStreetEdge(StreetEdge se) {
var props = Lists.newArrayList(
kv("permission", streetPermissionAsString(se.getPermission())),
kv("bicycleSafetyFactor", roundTo2Decimals(se.getBicycleSafetyFactor())),
kv("noThruTraffic", noThruTrafficAsString(se))
kv("noThruTraffic", noThruTrafficAsString(se)),
kv("wheelchairAccessible", se.isWheelchairAccessible())
);
if (se.hasBogusName()) {
props.addFirst(kv("name", "%s (generated)".formatted(se.getName().toString())));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class OsmWithTags {

private static final Set<String> LEVEL_TAGS = Set.of("level", "layer");
private static final Set<String> DEFAULT_LEVEL = Set.of("0");
private static final Consumer<String> NO_OP = i -> {};

/* To save memory this is only created when an entity actually has tags. */
private Map<String, String> tags;
Expand Down Expand Up @@ -220,6 +221,33 @@ public OptionalInt getTagAsInt(String tag, Consumer<String> errorHandler) {
return OptionalInt.empty();
}

/**
* Some tags are allowed to have values like 55, "true" or "false".
* <p>
* "true", "yes" is returned as 1.
* <p>
* "false", "no" is returned as 0
* <p>
* Everything else is returned as an emtpy optional.
*/
public OptionalInt parseIntOrBoolean(String tag, Consumer<String> errorHandler) {
var maybeInt = getTagAsInt(tag, NO_OP);
if (maybeInt.isPresent()) {
return maybeInt;
} else {
if (isTagTrue(tag)) {
return OptionalInt.of(1);
} else if (isTagFalse(tag)) {
return OptionalInt.of(0);
} else if (hasTag(tag)) {
errorHandler.accept(getTag(tag));
return OptionalInt.empty();
} else {
return OptionalInt.empty();
}
}
}

/**
* Checks is a tag contains the specified value.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package org.opentripplanner.graph_builder.module.osm;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.List;
import org.junit.jupiter.api.Test;
import org.opentripplanner._support.geometry.Coordinates;
import org.opentripplanner.framework.i18n.I18NString;
import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore;
import org.opentripplanner.osm.wayproperty.specifier.WayTestData;
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.street.model._data.StreetModelForTest;
import org.opentripplanner.street.model.vertex.IntersectionVertex;

class ParkingProcessorTest {

private static final IntersectionVertex INTERSECTION_VERTEX = StreetModelForTest.intersectionVertex(
1,
1
);
private static final ParkingProcessor PROCESSOR = new ParkingProcessor(
new Graph(),
DataImportIssueStore.NOOP,
(n, w) -> INTERSECTION_VERTEX
);

@Test
void noWheelchairParking() {
var entity = WayTestData.parkAndRide();
var parking = PROCESSOR.createVehicleParkingObjectFromOsmEntity(
true,
Coordinates.BERLIN,
entity,
I18NString.of("parking"),
List.of()
);

assertFalse(parking.hasWheelchairAccessibleCarPlaces());
assertNull(parking.getCapacity().getWheelchairAccessibleCarSpaces());
}

@Test
void wheelchairParking() {
var entity = WayTestData.parkAndRide();
entity.addTag("capacity:disabled", "yes");
var parking = PROCESSOR.createVehicleParkingObjectFromOsmEntity(
true,
Coordinates.BERLIN,
entity,
I18NString.of("parking"),
List.of()
);

assertTrue(parking.hasWheelchairAccessibleCarPlaces());
assertEquals(1, parking.getCapacity().getWheelchairAccessibleCarSpaces());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.OptionalInt;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.opentripplanner.osm.wayproperty.specifier.WayTestData;

public class OsmWithTagsTest {
Expand Down Expand Up @@ -272,4 +276,26 @@ void fallbackName() {
var namedTunnel = WayTestData.carTunnel();
assertFalse(namedTunnel.hasNoName());
}

private static List<Arguments> parseIntOrBooleanCases() {
return List.of(
Arguments.of("true", OptionalInt.of(1)),
Arguments.of("yes", OptionalInt.of(1)),
Arguments.of("no", OptionalInt.of(0)),
Arguments.of("false", OptionalInt.of(0)),
Arguments.of("0", OptionalInt.of(0)),
Arguments.of("12", OptionalInt.of(12)),
Arguments.of("", OptionalInt.empty())
);
}

@ParameterizedTest
@MethodSource("parseIntOrBooleanCases")
void parseIntOrBoolean(String value, OptionalInt expected) {
var way = new OsmWithTags();
var key = "capacity:disabled";
way.addTag(key, value);
var maybeInt = way.parseIntOrBoolean(key, i -> {});
assertEquals(expected, maybeInt);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -224,4 +224,12 @@ public static OsmWithTags indoor(String value) {
way.addTag("indoor", value);
return way;
}

public static OsmWithTags parkAndRide() {
var way = new OsmWithTags();
way.addTag("amenity", "parking");
way.addTag("park_ride", "yes");
way.addTag("capacity", "10");
return way;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,104 @@
"group" : "Other"
}
},
{
"id" : "wheelchair-accessible",
"source" : "vectorSource",
"source-layer" : "edges",
"type" : "line",
"minzoom" : 6,
"maxzoom" : 23,
"paint" : {
"line-color" : "#136b04",
"line-width" : [
"interpolate",
[
"linear"
],
[
"zoom"
],
13,
0.2,
23,
8.0
],
"line-offset" : [
"interpolate",
[
"linear"
],
[
"zoom"
],
13,
0.4,
23,
7.0
]
},
"filter" : [
"==",
"wheelchairAccessible",
true
],
"layout" : {
"line-cap" : "round",
"visibility" : "none"
},
"metadata" : {
"group" : "Wheelchair accessibility"
}
},
{
"id" : "wheelchair-inaccessible",
"source" : "vectorSource",
"source-layer" : "edges",
"type" : "line",
"minzoom" : 6,
"maxzoom" : 23,
"paint" : {
"line-color" : "#fc0f2a",
"line-width" : [
"interpolate",
[
"linear"
],
[
"zoom"
],
13,
0.2,
23,
8.0
],
"line-offset" : [
"interpolate",
[
"linear"
],
[
"zoom"
],
13,
0.4,
23,
7.0
]
},
"filter" : [
"==",
"wheelchairAccessible",
false
],
"layout" : {
"line-cap" : "round",
"visibility" : "none"
},
"metadata" : {
"group" : "Wheelchair accessibility"
}
},
{
"id" : "edge",
"type" : "line",
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/MapView/GeometryPropertyPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function GeometryPropertyPopup({
{Object.entries(properties).map(([key, value]) => (
<tr key={key}>
<th scope="row">{key}</th>
<td>{value}</td>
<td>{String(value)}</td>
</tr>
))}
</tbody>
Expand Down

0 comments on commit 7b4d240

Please sign in to comment.