From ea147aeb4eb293987b2bfc273c66c848017130f8 Mon Sep 17 00:00:00 2001 From: ratrun Date: Sat, 5 Aug 2023 17:01:41 +0200 Subject: [PATCH] Implementation for seasonal_restricted encoded value as suggested in #2477 --- .../java/com/graphhopper/GraphHopper.java | 2 + .../ConditionalOSMTagInspector.java | 13 ++++-- .../osm/conditional/ConditionalParser.java | 4 +- .../ev/DefaultEncodedValueFactory.java | 2 + .../routing/ev/SeasonalRestricted.java | 26 +++++++++++ .../routing/util/EncodingManager.java | 3 +- .../parsers/OSMSeasonalRestrictedParser.java | 46 +++++++++++++++++++ .../reader/osm/GraphHopperOSMTest.java | 4 +- .../OSMSeasonalRestrictedParserTest.java | 45 ++++++++++++++++++ 9 files changed, 138 insertions(+), 7 deletions(-) create mode 100644 core/src/main/java/com/graphhopper/routing/ev/SeasonalRestricted.java create mode 100644 core/src/main/java/com/graphhopper/routing/util/parsers/OSMSeasonalRestrictedParser.java create mode 100644 core/src/test/java/com/graphhopper/routing/util/parsers/OSMSeasonalRestrictedParserTest.java diff --git a/core/src/main/java/com/graphhopper/GraphHopper.java b/core/src/main/java/com/graphhopper/GraphHopper.java index e3bd18f2585..576fb69a1d0 100644 --- a/core/src/main/java/com/graphhopper/GraphHopper.java +++ b/core/src/main/java/com/graphhopper/GraphHopper.java @@ -646,6 +646,8 @@ protected OSMParsers buildOSMParsers(Map vehiclesByName, List tagsToCheck, this(Arrays.asList(new DateRangeParser(value)), tagsToCheck, restrictiveValues, permittedValues, false); } + public ConditionalOSMTagInspector(List tagsToCheck, + Set restrictiveValues, Set permittedValues) { + this(null, tagsToCheck, restrictiveValues, permittedValues, false); + } + public ConditionalOSMTagInspector(List valueParsers, List tagsToCheck, Set restrictiveValues, Set permittedValues, boolean enabledLogs) { this.tagsToCheck = new ArrayList<>(tagsToCheck.size()); @@ -54,9 +59,11 @@ public ConditionalOSMTagInspector(List valuePa boolean logUnsupportedFeatures = false; this.permitParser = new ConditionalParser(permittedValues, logUnsupportedFeatures); this.restrictiveParser = new ConditionalParser(restrictiveValues, logUnsupportedFeatures); - for (ConditionalValueParser cvp : valueParsers) { - permitParser.addConditionalValueParser(cvp); - restrictiveParser.addConditionalValueParser(cvp); + if (valueParsers != null) { + for (ConditionalValueParser cvp : valueParsers) { + permitParser.addConditionalValueParser(cvp); + restrictiveParser.addConditionalValueParser(cvp); + } } } diff --git a/core/src/main/java/com/graphhopper/reader/osm/conditional/ConditionalParser.java b/core/src/main/java/com/graphhopper/reader/osm/conditional/ConditionalParser.java index 1b67a29e08e..55863a4b59f 100644 --- a/core/src/main/java/com/graphhopper/reader/osm/conditional/ConditionalParser.java +++ b/core/src/main/java/com/graphhopper/reader/osm/conditional/ConditionalParser.java @@ -22,7 +22,6 @@ import java.text.ParseException; import java.util.ArrayList; -import java.util.Calendar; import java.util.List; import java.util.Set; @@ -108,6 +107,9 @@ public boolean checkCondition(String conditionalTag) throws ParseException { if (conditionalTag == null || conditionalTag.isEmpty() || !conditionalTag.contains("@")) return false; + if (valueParsers.size() == 0) + return true; + if (conditionalTag.contains(";")) { if (enabledLogs) logger.warn("We do not support multiple conditions yet: " + conditionalTag); diff --git a/core/src/main/java/com/graphhopper/routing/ev/DefaultEncodedValueFactory.java b/core/src/main/java/com/graphhopper/routing/ev/DefaultEncodedValueFactory.java index 67b03984802..45d1175c9c4 100644 --- a/core/src/main/java/com/graphhopper/routing/ev/DefaultEncodedValueFactory.java +++ b/core/src/main/java/com/graphhopper/routing/ev/DefaultEncodedValueFactory.java @@ -25,6 +25,8 @@ public class DefaultEncodedValueFactory implements EncodedValueFactory { public EncodedValue create(String name, PMap properties) { if (Roundabout.KEY.equals(name)) { return Roundabout.create(); + } else if (SeasonalRestricted.KEY.equals(name)) { + return SeasonalRestricted.create(); } else if (GetOffBike.KEY.equals(name)) { return GetOffBike.create(); } else if (RoadClass.KEY.equals(name)) { diff --git a/core/src/main/java/com/graphhopper/routing/ev/SeasonalRestricted.java b/core/src/main/java/com/graphhopper/routing/ev/SeasonalRestricted.java new file mode 100644 index 00000000000..23b70046445 --- /dev/null +++ b/core/src/main/java/com/graphhopper/routing/ev/SeasonalRestricted.java @@ -0,0 +1,26 @@ +/* + * Licensed to GraphHopper GmbH under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * GraphHopper GmbH licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.graphhopper.routing.ev; + +public class SeasonalRestricted { + public static final String KEY = "seasonal_restricted"; + + public static BooleanEncodedValue create() { + return new SimpleBooleanEncodedValue(KEY); + } +} diff --git a/core/src/main/java/com/graphhopper/routing/util/EncodingManager.java b/core/src/main/java/com/graphhopper/routing/util/EncodingManager.java index aa11e34647b..6f2297ea188 100644 --- a/core/src/main/java/com/graphhopper/routing/util/EncodingManager.java +++ b/core/src/main/java/com/graphhopper/routing/util/EncodingManager.java @@ -169,7 +169,8 @@ private void addDefaultEncodedValues() { RoadEnvironment.KEY, MaxSpeed.KEY, RoadAccess.KEY, - FerrySpeed.KEY + FerrySpeed.KEY, + SeasonalRestricted.KEY )); if (em.getVehicles().stream().anyMatch(vehicle -> vehicle.contains("bike") || vehicle.contains("mtb") || vehicle.contains("racingbike"))) { keys.add(BikeNetwork.KEY); diff --git a/core/src/main/java/com/graphhopper/routing/util/parsers/OSMSeasonalRestrictedParser.java b/core/src/main/java/com/graphhopper/routing/util/parsers/OSMSeasonalRestrictedParser.java new file mode 100644 index 00000000000..0db6c86744e --- /dev/null +++ b/core/src/main/java/com/graphhopper/routing/util/parsers/OSMSeasonalRestrictedParser.java @@ -0,0 +1,46 @@ +package com.graphhopper.routing.util.parsers; + +import com.graphhopper.reader.ReaderWay; +import com.graphhopper.reader.osm.conditional.ConditionalOSMTagInspector; +import com.graphhopper.reader.osm.conditional.ConditionalTagInspector; +import com.graphhopper.routing.ev.BooleanEncodedValue; +import com.graphhopper.routing.ev.EdgeIntAccess; +import com.graphhopper.storage.IntsRef; + +import java.util.*; + +/** + * This parser scans different OSM conditional tags to identify if a way has only conditional access + */ +public class OSMSeasonalRestrictedParser implements TagParser { + + private final BooleanEncodedValue seasonalRestrictedEnc; + private final ConditionalTagInspector acceptor = new ConditionalOSMTagInspector(getConditionalTags(), getSampleRestrictedValues(), new HashSet<>()); + + /** + * @param seasonalRestrictedEnc used to find out if way access is conditional + */ + public OSMSeasonalRestrictedParser(BooleanEncodedValue seasonalRestrictedEnc) { + this.seasonalRestrictedEnc = seasonalRestrictedEnc; + } + + private static Set getSampleRestrictedValues() { + Set restrictedValues = new HashSet<>(); + restrictedValues.add("no"); + restrictedValues.add("restricted"); + return restrictedValues; + } + + private static List getConditionalTags() { + List conditionalTags = new ArrayList<>(); + conditionalTags.add("vehicle"); + conditionalTags.add("access"); + return conditionalTags; + } + + @Override + public void handleWayTags(int edgeId, EdgeIntAccess edgeIntAccess, ReaderWay way, IntsRef relationFlags) { + boolean isSeasonalRestricted = acceptor.isPermittedWayConditionallyRestricted(way); + seasonalRestrictedEnc.setBool(false, edgeId, edgeIntAccess, isSeasonalRestricted); + } +} diff --git a/core/src/test/java/com/graphhopper/reader/osm/GraphHopperOSMTest.java b/core/src/test/java/com/graphhopper/reader/osm/GraphHopperOSMTest.java index 5ae254a30c8..9bd444e067b 100644 --- a/core/src/test/java/com/graphhopper/reader/osm/GraphHopperOSMTest.java +++ b/core/src/test/java/com/graphhopper/reader/osm/GraphHopperOSMTest.java @@ -518,7 +518,7 @@ public void testNothingHappensWhenFlagEncodersAreChangedForLoad() { setGraphHopperLocation(ghLoc); instance.load(); assertEquals(5, instance.getBaseGraph().getNodes()); - assertEquals("foot_access,foot_average_speed,foot_priority,car_access,car_average_speed,foot_subnetwork,car_subnetwork,roundabout,road_class,road_class_link,road_environment,max_speed,road_access,ferry_speed,foot_network", + assertEquals("foot_access,foot_average_speed,foot_priority,car_access,car_average_speed,foot_subnetwork,car_subnetwork,roundabout,road_class,road_class_link,road_environment,max_speed,road_access,ferry_speed,seasonal_restricted,foot_network", instance.getEncodingManager().getEncodedValues().stream().map(EncodedValue::getName).collect(Collectors.joining(","))); } @@ -558,7 +558,7 @@ public void testFailsForWrongEVConfig() { setOSMFile(testOsm3); instance.load(); assertEquals(5, instance.getBaseGraph().getNodes()); - assertEquals("foot_access,foot_average_speed,foot_priority,car_access,car_average_speed,foot_subnetwork,car_subnetwork,roundabout,road_class,road_class_link,road_environment,max_speed,road_access,ferry_speed,foot_network", instance.getEncodingManager().getEncodedValues().stream().map(EncodedValue::getName).collect(Collectors.joining(","))); + assertEquals("foot_access,foot_average_speed,foot_priority,car_access,car_average_speed,foot_subnetwork,car_subnetwork,roundabout,road_class,road_class_link,road_environment,max_speed,road_access,ferry_speed,seasonal_restricted,foot_network", instance.getEncodingManager().getEncodedValues().stream().map(EncodedValue::getName).collect(Collectors.joining(","))); } @Test diff --git a/core/src/test/java/com/graphhopper/routing/util/parsers/OSMSeasonalRestrictedParserTest.java b/core/src/test/java/com/graphhopper/routing/util/parsers/OSMSeasonalRestrictedParserTest.java new file mode 100644 index 00000000000..a96364c9a33 --- /dev/null +++ b/core/src/test/java/com/graphhopper/routing/util/parsers/OSMSeasonalRestrictedParserTest.java @@ -0,0 +1,45 @@ +package com.graphhopper.routing.util.parsers; + +import com.graphhopper.reader.ReaderWay; +import com.graphhopper.routing.ev.*; +import com.graphhopper.storage.IntsRef; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class OSMSeasonalRestrictedParserTest { + private BooleanEncodedValue seasonalRestrictedEnc; + private OSMSeasonalRestrictedParser parser; + + @BeforeEach + public void setUp() { + seasonalRestrictedEnc = SeasonalRestricted.create(); + seasonalRestrictedEnc.init(new EncodedValue.InitializerConfig()); + parser = new OSMSeasonalRestrictedParser(seasonalRestrictedEnc); + } + + @Test + public void testSeasonalRestrictedTags() { + IntsRef relFlags = new IntsRef(2); + + ReaderWay readerWay = new ReaderWay(1); + EdgeIntAccess edgeIntAccess = new ArrayEdgeIntAccess(1); + int edgeId = 0; + readerWay.setTag("highway", "primary"); + parser.handleWayTags(edgeId, edgeIntAccess, readerWay, relFlags); + assertFalse(seasonalRestrictedEnc.getBool(false, edgeId, edgeIntAccess)); + + readerWay.setTag("access:conditional", "no @ Winter"); + parser.handleWayTags(edgeId, edgeIntAccess, readerWay, relFlags); + assertTrue(seasonalRestrictedEnc.getBool(false, edgeId, edgeIntAccess)); + + readerWay.setTag("access:conditional", "no @ Nov-Apr"); + parser.handleWayTags(edgeId, edgeIntAccess, readerWay, relFlags); + assertTrue(seasonalRestrictedEnc.getBool(false, edgeId, edgeIntAccess)); + + readerWay.setTag("access:conditional", "no @ (Nov-Apr; May 19:30-06:00; Jun-Aug 20:30-05:30; Sep-Oct 19:30-06:00)"); + parser.handleWayTags(edgeId, edgeIntAccess, readerWay, relFlags); + assertTrue(seasonalRestrictedEnc.getBool(false, edgeId, edgeIntAccess)); + } +}