diff --git a/core/src/main/java/com/graphhopper/reader/ConditionalInspector.java b/core/src/main/java/com/graphhopper/reader/ConditionalInspector.java new file mode 100644 index 00000000000..f62060367a8 --- /dev/null +++ b/core/src/main/java/com/graphhopper/reader/ConditionalInspector.java @@ -0,0 +1,27 @@ +/* + * 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.reader; + +/** + * @author Andrzej Oles + */ +public interface ConditionalInspector { + boolean hasLazyEvaluatedConditions(); + + String getTagValue(); +} diff --git a/core/src/main/java/com/graphhopper/reader/ConditionalSpeedInspector.java b/core/src/main/java/com/graphhopper/reader/ConditionalSpeedInspector.java index 45795590f56..097b255dfd5 100644 --- a/core/src/main/java/com/graphhopper/reader/ConditionalSpeedInspector.java +++ b/core/src/main/java/com/graphhopper/reader/ConditionalSpeedInspector.java @@ -20,10 +20,6 @@ /** * @author Andrzej Oles */ -public interface ConditionalSpeedInspector { +public interface ConditionalSpeedInspector extends ConditionalInspector{ boolean hasConditionalSpeed(ReaderWay way); - - boolean isConditionLazyEvaluated(); - - String getTagValue(); } diff --git a/core/src/main/java/com/graphhopper/reader/ConditionalTagInspector.java b/core/src/main/java/com/graphhopper/reader/ConditionalTagInspector.java index eb8a127f58c..525ad49dfd3 100644 --- a/core/src/main/java/com/graphhopper/reader/ConditionalTagInspector.java +++ b/core/src/main/java/com/graphhopper/reader/ConditionalTagInspector.java @@ -20,12 +20,8 @@ /** * @author Peter Karich */ -public interface ConditionalTagInspector { +public interface ConditionalTagInspector extends ConditionalInspector { boolean isRestrictedWayConditionallyPermitted(ReaderWay way); boolean isPermittedWayConditionallyRestricted(ReaderWay way); - - boolean isConditionLazyEvaluated(); - - String getTagValue(); } diff --git a/core/src/main/java/com/graphhopper/reader/osm/conditional/ConditionalOSMSpeedInspector.java b/core/src/main/java/com/graphhopper/reader/osm/conditional/ConditionalOSMSpeedInspector.java index 1e5863c5636..426d2aa92f7 100644 --- a/core/src/main/java/com/graphhopper/reader/osm/conditional/ConditionalOSMSpeedInspector.java +++ b/core/src/main/java/com/graphhopper/reader/osm/conditional/ConditionalOSMSpeedInspector.java @@ -39,6 +39,7 @@ public class ConditionalOSMSpeedInspector implements ConditionalSpeedInspector { private boolean enabledLogs = true; private String val; + private boolean isLazyEvaluated; @Override public String getTagValue() { @@ -71,10 +72,11 @@ public boolean hasConditionalSpeed(ReaderWay way) { if (val == null || val.isEmpty()) continue; try { - if (parser.checkCondition(val)) { - val = parser.getRestrictions(); + ConditionalParser.Result result = parser.checkCondition(val); + isLazyEvaluated = result.isLazyEvaluated(); + val = result.getRestrictions(); + if (result.isCheckPassed() || isLazyEvaluated) return true; - } } catch (Exception e) { if (enabledLogs) { logger.warn("for way " + way.getId() + " could not parse the conditional value '" + val + "' of tag '" + tagToCheck + "'. Exception:" + e.getMessage()); @@ -85,8 +87,8 @@ public boolean hasConditionalSpeed(ReaderWay way) { } @Override - public boolean isConditionLazyEvaluated() { - return parser.hasUnevaluatedRestrictions(); + public boolean hasLazyEvaluatedConditions() { + return isLazyEvaluated; } } diff --git a/core/src/main/java/com/graphhopper/reader/osm/conditional/ConditionalOSMTagInspector.java b/core/src/main/java/com/graphhopper/reader/osm/conditional/ConditionalOSMTagInspector.java index 29e3ebb505c..d41eb5fbf23 100644 --- a/core/src/main/java/com/graphhopper/reader/osm/conditional/ConditionalOSMTagInspector.java +++ b/core/src/main/java/com/graphhopper/reader/osm/conditional/ConditionalOSMTagInspector.java @@ -80,12 +80,11 @@ public boolean isPermittedWayConditionallyRestricted(ReaderWay way) { } @Override - public boolean isConditionLazyEvaluated() { + public boolean hasLazyEvaluatedConditions() { return isLazyEvaluated; } protected boolean applies(ReaderWay way, ConditionalParser parser) { - isLazyEvaluated = false; for (int index = 0; index < tagsToCheck.size(); index++) { String tagToCheck = tagsToCheck.get(index); @@ -93,12 +92,12 @@ protected boolean applies(ReaderWay way, ConditionalParser parser) { if (val == null || val.isEmpty()) continue; try { - if (parser.checkCondition(val)) { - if (parser.hasUnevaluatedRestrictions()) - isLazyEvaluated = true; - val = parser.getRestrictions(); - return true; - } + ConditionalParser.Result result = parser.checkCondition(val); + isLazyEvaluated = result.isLazyEvaluated(); + val = result.getRestrictions(); + // allow the check result to be false but still have unevaluated conditions + if (result.isCheckPassed() || isLazyEvaluated) + return result.isCheckPassed(); } catch (Exception e) { if (enabledLogs) { // log only if no date ala 21:00 as currently date and numbers do not support time precise restrictions 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 c2b4b7089b4..bae5d162181 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 @@ -42,10 +42,7 @@ public class ConditionalParser { private final Set restrictedValues; private final List valueParsers = new ArrayList<>(5); private final boolean enabledLogs; - - private String simpleValue; - private String unevaluatedRestrictions = ""; - private Conditions unevaluatedConditions; + private final String simpleValue; public ConditionalParser(Set restrictedValues) { this(restrictedValues, false); @@ -55,12 +52,7 @@ public ConditionalParser(Set restrictedValues, boolean enabledLogs) { // use map => key & type (date vs. double) this.restrictedValues = restrictedValues; this.enabledLogs = enabledLogs; - - if (hasRestrictedValues()) { - if (restrictedValues.contains("yes")) - this.simpleValue = "yes"; - else this.simpleValue = "no"; - } + this.simpleValue = hasRestrictedValues() && restrictedValues.contains("yes") ? "yes" : "no"; } public static ConditionalValueParser createNumberParser(final String assertKey, final Number obj) { @@ -155,38 +147,112 @@ public ConditionalParser setConditionalValueParser(ConditionalValueParser vp) { } // attempt to parse the value with any of the registered parsers - private boolean checkAtomicCondition(Condition condition) throws ParseException { - for (ConditionalValueParser valueParser : valueParsers) { - ConditionalValueParser.ConditionState c = valueParser.checkCondition(condition); - if (c.isValid()) { - if (c.isEvaluated()) - return c.isCheckPassed(); - else { // condition could not be evaluated but might evaluate to true during query - unevaluatedConditions.addCondition(c.getCondition()); - return true; + private ParsedCondition checkAtomicCondition(Condition condition, ParsedCondition parsedCondition) throws ParseException { + parsedCondition.reset(); + try { + for (ConditionalValueParser valueParser : valueParsers) { + ConditionalValueParser.ConditionState conditionState = valueParser.checkCondition(condition); + if (conditionState.isValid()) { + parsedCondition.setValid(true); + if (conditionState.isEvaluated()) { + parsedCondition.setEvaluated(true); + parsedCondition.setCheckPassed(conditionState.isCheckPassed()); + break; + } else { // condition could not be evaluated but might evaluate to true during query + parsedCondition.setLazyEvaluated(true); + parsedCondition.getLazyEvaluatedConditions().add(conditionState.getCondition()); + } } } } - return false; + catch (ParseException e) { + throw e; + } + finally { + return parsedCondition; + } + } + + class ParsedCondition { + private boolean valid; + private boolean evaluated; + private boolean checkPassed; + private boolean lazyEvaluated; + private ArrayList lazyEvaluatedConditions = new ArrayList(); + + void reset() { + valid = evaluated = checkPassed = lazyEvaluated = false; + } + + void setValid(boolean valid) { + this.valid = valid; + } + + void setEvaluated(boolean evaluated) { + this.evaluated = evaluated; + } + + void setCheckPassed(boolean checkPassed) { + this.checkPassed = checkPassed; + } + + void setLazyEvaluated(boolean lazyEvaluated) { + this.lazyEvaluated = lazyEvaluated; + } + + boolean isValid() { + return valid; + } + + boolean isEvaluated() { + return evaluated; + } + + boolean isCheckPassed() { + return checkPassed; + } + + boolean isLazyEvaluated() { + return lazyEvaluated; + } + + boolean isInvalidOrFalse() { + return !valid || (!lazyEvaluated && evaluated && !checkPassed); + } + + ArrayList getLazyEvaluatedConditions() { + return lazyEvaluatedConditions; + } } // all of the combined conditions need to be met - private boolean checkCombinedCondition(List conditions) throws ParseException { + private ParsedCondition checkCombinedCondition(Restriction restriction) throws ParseException { + ParsedCondition parsedCondition = new ParsedCondition(); // combined conditions, must be all matched - for (Condition condition: conditions) { - if (!checkAtomicCondition(condition)) - return false; + boolean checkPassed = true; + boolean lazyEvaluated = false; + for (Condition condition: restriction.getConditions()) { + parsedCondition = checkAtomicCondition(condition, parsedCondition); + checkPassed = checkPassed && parsedCondition.isCheckPassed(); + if (parsedCondition.isInvalidOrFalse()) { + lazyEvaluated = false; + break; + } + if (parsedCondition.isLazyEvaluated()) + lazyEvaluated = true; } - return true; + parsedCondition.setLazyEvaluated(lazyEvaluated); + parsedCondition.setCheckPassed(checkPassed); + return parsedCondition; } - public boolean checkCondition(String tagValue) throws ParseException { + public Result checkCondition(String tagValue) throws ParseException { + Result result = new Result(); if (tagValue == null || tagValue.isEmpty() || !tagValue.contains("@")) - return false; + return result; ArrayList parsedRestrictions = new ArrayList<>(); - unevaluatedRestrictions = ""; try { ConditionalRestrictionParser parser = new ConditionalRestrictionParser(new ByteArrayInputStream(tagValue.getBytes())); @@ -200,52 +266,40 @@ public boolean checkCondition(String tagValue) throws ParseException { String restrictionValue = restriction.getValue(); if (hasRestrictedValues()) { - // check whether the encountered value is on the list - if (!restrictedValues.contains(restrictionValue)) + if (restrictedValues.contains(restrictionValue)) + restrictionValue = simpleValue; + else continue; } else { - simpleValue = restrictionValue; + result.setRestrictions(restrictionValue); } - List conditions = restriction.getConditions(); - - unevaluatedConditions = new Conditions(new ArrayList(), restriction.inParen()); + ParsedCondition parsedConditions = checkCombinedCondition(restriction); + boolean checkPassed = parsedConditions.isCheckPassed(); + result.setCheckPassed(result.isCheckPassed() || checkPassed); - if (checkCombinedCondition(conditions)) { - // check for unevaluated conditions - if (unevaluatedConditions.getConditions().isEmpty()) { - return true; // terminate once the first matching condition which can be fully evaluated is encountered - } - else { - parsedRestrictions.add(new Restriction(simpleValue, unevaluatedConditions)); - } + // check for unevaluated conditions + if (!parsedConditions.isLazyEvaluated()) { + if (checkPassed) + return result; // terminate once the first matching condition which can be fully evaluated is encountered + } + else { + parsedRestrictions.add(0, new Restriction(restrictionValue, new Conditions(parsedConditions.getLazyEvaluatedConditions(), restriction.inParen()))); } } } catch (ch.poole.conditionalrestrictionparser.ParseException e) { if (enabledLogs) logger.warn("Parser exception for " + tagValue + " " + e.toString()); - return false; - } - // at this point either no matching restriction was found or the encountered restrictions need to be lazy evaluated - if (parsedRestrictions.isEmpty()) { - return false; - } - else { - unevaluatedRestrictions = Util.restrictionsToString(parsedRestrictions); - return true; + return result; } - } - public String getRestrictions() { - if (hasUnevaluatedRestrictions()) - return unevaluatedRestrictions; - else - return simpleValue; - } + if (!parsedRestrictions.isEmpty()) { + result.setRestrictions(Util.restrictionsToString(parsedRestrictions)); + result.setLazyEvaluated(true); + } - public boolean hasUnevaluatedRestrictions() { - return !unevaluatedRestrictions.isEmpty(); + return result; } protected static double parseNumber(String str) { @@ -260,4 +314,34 @@ protected static double parseNumber(String str) { private boolean hasRestrictedValues() { return !( restrictedValues==null || restrictedValues.isEmpty() ); } + + class Result { + private boolean checkPassed; + private boolean lazyEvaluated; + private String restrictions; + + boolean isCheckPassed() { + return checkPassed; + } + + void setCheckPassed(boolean checkPassed) { + this.checkPassed = checkPassed; + } + + boolean isLazyEvaluated() { + return lazyEvaluated; + } + + void setLazyEvaluated(boolean lazyEvaluated) { + this.lazyEvaluated = lazyEvaluated; + } + + String getRestrictions() { + return restrictions; + } + + void setRestrictions(String restrictions) { + this.restrictions = restrictions; + } + } } diff --git a/core/src/main/java/com/graphhopper/routing/TDAStar.java b/core/src/main/java/com/graphhopper/routing/TDAStar.java index be0452f7445..0c22178c128 100644 --- a/core/src/main/java/com/graphhopper/routing/TDAStar.java +++ b/core/src/main/java/com/graphhopper/routing/TDAStar.java @@ -17,6 +17,7 @@ */ package com.graphhopper.routing; +import com.graphhopper.routing.util.ConditionalAccessEdgeFilter; import com.graphhopper.routing.util.TraversalMode; import com.graphhopper.routing.weighting.Weighting; import com.graphhopper.storage.Graph; @@ -35,6 +36,10 @@ public class TDAStar extends AStar { public TDAStar(Graph graph, Weighting weighting, TraversalMode tMode) { super(graph, weighting, tMode); + if (flagEncoder.hasEncodedValue(flagEncoder.toString()+"-conditional_access")) { + inEdgeExplorer = graph.createEdgeExplorer(ConditionalAccessEdgeFilter.inEdges(flagEncoder)); + outEdgeExplorer = graph.createEdgeExplorer(ConditionalAccessEdgeFilter.outEdges(flagEncoder)); + } if (!weighting.isTimeDependent()) throw new RuntimeException("A time-dependent routing algorithm requires a time-dependent weighting."); } diff --git a/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java index eef8a7ac2bd..0ca071a8993 100644 --- a/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java +++ b/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java @@ -24,6 +24,7 @@ import com.graphhopper.reader.ReaderWay; import com.graphhopper.reader.osm.conditional.ConditionalOSMTagInspector; import com.graphhopper.reader.osm.conditional.ConditionalParser; +import com.graphhopper.reader.osm.conditional.DateRangeParser; import com.graphhopper.routing.profiles.*; import com.graphhopper.routing.weighting.TurnWeighting; import com.graphhopper.storage.IntsRef; @@ -119,6 +120,8 @@ protected AbstractFlagEncoder(int speedBits, double speedFactor, int maxTurnCost protected void init() { // we should move 'OSM to object' logic into the DataReader like OSMReader, but this is a major task as we need to convert OSM format into kind of a standard/generic format ConditionalOSMTagInspector conditionalTagInspector = new ConditionalOSMTagInspector(restrictions, restrictedValues, intendedValues); + conditionalTagInspector.addValueParser(new DateRangeParser()); + //DateTime parser needs to go last = have highest priority in order to allow for storing unevaluated conditionals conditionalTagInspector.addValueParser(ConditionalParser.createDateTimeParser()); this.conditionalTagInspector = conditionalTagInspector; } @@ -658,22 +661,24 @@ public boolean hasEncodedValue(String key) { } public EncodingManager.Access isRestrictedWayConditionallyPermitted(ReaderWay way) { - if (getConditionalTagInspector().isRestrictedWayConditionallyPermitted(way)) - if (getConditionalTagInspector().isConditionLazyEvaluated()) - return EncodingManager.Access.CONDITIONAL; - else - return EncodingManager.Access.WAY; - else - return EncodingManager.Access.CAN_SKIP; + return isRestrictedWayConditionallyPermitted(way, EncodingManager.Access.WAY); + } + + public EncodingManager.Access isRestrictedWayConditionallyPermitted(ReaderWay way, EncodingManager.Access accept) { + return getConditionalAccess(way, accept, true); } public EncodingManager.Access isPermittedWayConditionallyRestricted(ReaderWay way) { - if (getConditionalTagInspector().isPermittedWayConditionallyRestricted(way)) - if (getConditionalTagInspector().isConditionLazyEvaluated()) - return EncodingManager.Access.CONDITIONAL; - else - return EncodingManager.Access.CAN_SKIP; + return getConditionalAccess(way, EncodingManager.Access.WAY, false); + } + + private EncodingManager.Access getConditionalAccess(ReaderWay way, EncodingManager.Access accept, boolean permissive) { + ConditionalTagInspector conditionalTagInspector = getConditionalTagInspector(); + boolean access = permissive ? conditionalTagInspector.isRestrictedWayConditionallyPermitted(way) : + !conditionalTagInspector.isPermittedWayConditionallyRestricted(way); + if (conditionalTagInspector.hasLazyEvaluatedConditions()) + return access ? EncodingManager.Access.PERMITTED : EncodingManager.Access.RESTRICTED; else - return EncodingManager.Access.WAY; + return access ? accept : EncodingManager.Access.CAN_SKIP; } } diff --git a/core/src/main/java/com/graphhopper/routing/util/BikeCommonFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/BikeCommonFlagEncoder.java index 017ecc127df..473b50ed8a6 100644 --- a/core/src/main/java/com/graphhopper/routing/util/BikeCommonFlagEncoder.java +++ b/core/src/main/java/com/graphhopper/routing/util/BikeCommonFlagEncoder.java @@ -251,14 +251,8 @@ public EncodingManager.Access getAccess(ReaderWay way) { accept = EncodingManager.Access.WAY; if (!accept.canSkip()) { - if (way.hasTag(restrictions, restrictedValues)) { - if (getConditionalTagInspector().isRestrictedWayConditionallyPermitted(way)) { - if (getConditionalTagInspector().isConditionLazyEvaluated()) - return EncodingManager.Access.CONDITIONAL; - } - else - return EncodingManager.Access.CAN_SKIP; - } + if (way.hasTag(restrictions, restrictedValues)) + accept = isRestrictedWayConditionallyPermitted(way, accept); return accept; } diff --git a/core/src/main/java/com/graphhopper/routing/util/CarFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/CarFlagEncoder.java index 2bd3c3c1c22..4e4b4c4c533 100644 --- a/core/src/main/java/com/graphhopper/routing/util/CarFlagEncoder.java +++ b/core/src/main/java/com/graphhopper/routing/util/CarFlagEncoder.java @@ -267,7 +267,7 @@ public IntsRef handleWayTags(IntsRef edgeFlags, ReaderWay way, EncodingManager.A // TODO: save conditional speeds only if their value is different from the default speed if (getConditionalSpeedInspector().hasConditionalSpeed(way)) - if (getConditionalSpeedInspector().isConditionLazyEvaluated()) + if (getConditionalSpeedInspector().hasLazyEvaluatedConditions()) conditionalSpeedEncoder.setBool(false, edgeFlags, true); else // conditional maxspeed overrides unconditional one @@ -279,15 +279,16 @@ public IntsRef handleWayTags(IntsRef edgeFlags, ReaderWay way, EncodingManager.A if (speedTwoDirections) setSpeed(true, edgeFlags, speed); + boolean access = !accept.isRestricted(); boolean isRoundabout = roundaboutEnc.getBool(false, edgeFlags); if (isOneway(way) || isRoundabout) { if (isForwardOneway(way)) - accessEnc.setBool(false, edgeFlags, true); + accessEnc.setBool(false, edgeFlags, access); if (isBackwardOneway(way)) - accessEnc.setBool(true, edgeFlags, true); + accessEnc.setBool(true, edgeFlags, access); } else { - accessEnc.setBool(false, edgeFlags, true); - accessEnc.setBool(true, edgeFlags, true); + accessEnc.setBool(false, edgeFlags, access); + accessEnc.setBool(true, edgeFlags, access); } if (accept.isConditional()) diff --git a/core/src/main/java/com/graphhopper/routing/util/ConditionalAccessEdgeFilter.java b/core/src/main/java/com/graphhopper/routing/util/ConditionalAccessEdgeFilter.java index a64bef4de85..41c6906e147 100644 --- a/core/src/main/java/com/graphhopper/routing/util/ConditionalAccessEdgeFilter.java +++ b/core/src/main/java/com/graphhopper/routing/util/ConditionalAccessEdgeFilter.java @@ -1,102 +1,120 @@ +/* + * 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.util; -import ch.poole.conditionalrestrictionparser.Condition; -import ch.poole.conditionalrestrictionparser.ConditionalRestrictionParser; -import ch.poole.conditionalrestrictionparser.Restriction; -import com.graphhopper.routing.EdgeKeys; import com.graphhopper.routing.profiles.BooleanEncodedValue; -import com.graphhopper.util.DateTimeHelper; -import com.graphhopper.storage.ConditionalEdgesMap; -import com.graphhopper.storage.GraphHopperStorage; import com.graphhopper.util.EdgeIteratorState; -import java.io.ByteArrayInputStream; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.List; - /** - * Filter out temporarily blocked edges - * + * @author Peter Karich * @author Andrzej Oles */ -public class ConditionalAccessEdgeFilter implements TimeDependentEdgeFilter { - private final BooleanEncodedValue conditionalEnc; - private final ConditionalEdgesMap conditionalEdges; - private final boolean fwd; +public class ConditionalAccessEdgeFilter implements EdgeFilter { + private static int DEFAULT_FILTER_ID = 0; private final boolean bwd; - private final DateTimeHelper dateTimeHelper; - - public ConditionalAccessEdgeFilter(GraphHopperStorage graph, FlagEncoder encoder) { - this(graph, encoder.toString()); - } - - public ConditionalAccessEdgeFilter(GraphHopperStorage graph, String encoderName) { - this(graph, encoderName, true, true); - } - - ConditionalAccessEdgeFilter(GraphHopperStorage graph, String encoderName, boolean fwd, boolean bwd) { - EncodingManager encodingManager = graph.getEncodingManager(); - conditionalEnc = encodingManager.getBooleanEncodedValue(EncodingManager.getKey(encoderName, "conditional_access")); - conditionalEdges = graph.getConditionalAccess(encoderName); + private final boolean fwd; + private final BooleanEncodedValue accessEnc; + private final BooleanEncodedValue conditionalEnc; + /** + * Used to be able to create non-equal filter instances with equal access encoder and fwd/bwd flags. + */ + private int filterId; + + private ConditionalAccessEdgeFilter(BooleanEncodedValue accessEnc, BooleanEncodedValue conditionalEnc, boolean fwd, boolean bwd, int filterId) { + this.accessEnc = accessEnc; + this.conditionalEnc = conditionalEnc; this.fwd = fwd; this.bwd = bwd; - this.dateTimeHelper = new DateTimeHelper(graph); + this.filterId = filterId; } - @Override - public final boolean accept(EdgeIteratorState iter, long time) { - if (fwd && iter.get(conditionalEnc) || bwd && iter.getReverse(conditionalEnc)) { - int edgeId = EdgeKeys.getOriginalEdge(iter); - // for now the filter is used only in the context of fwd search so only edges going out of the base node are explored - ZonedDateTime zonedDateTime = dateTimeHelper.getZonedDateTime(iter, time); - String value = conditionalEdges.getValue(edgeId); - return accept(value, zonedDateTime); - } - return true; + private ConditionalAccessEdgeFilter(FlagEncoder flagEncoder, boolean fwd, boolean bwd, int filterId) { + this(flagEncoder.getAccessEnc(), flagEncoder.getBooleanEncodedValue(flagEncoder.toString()+"-conditional_access"), fwd, bwd, filterId); } - boolean accept(String conditional, ZonedDateTime zonedDateTime) { - boolean matchValue = false; - - try { - ConditionalRestrictionParser crparser = new ConditionalRestrictionParser(new ByteArrayInputStream(conditional.getBytes())); + public static ConditionalAccessEdgeFilter outEdges(BooleanEncodedValue accessEnc, BooleanEncodedValue conditionalEnc) { + return new ConditionalAccessEdgeFilter(accessEnc, conditionalEnc, true, false, DEFAULT_FILTER_ID); + } - ArrayList restrictions = crparser.restrictions(); + public static ConditionalAccessEdgeFilter inEdges(BooleanEncodedValue accessEnc, BooleanEncodedValue conditionalEnc) { + return new ConditionalAccessEdgeFilter(accessEnc, conditionalEnc, false, true, DEFAULT_FILTER_ID); + } - // iterate over restrictions starting from the last one in order to match to the most specific one - for (int i = restrictions.size() - 1 ; i >= 0; i--) { - Restriction restriction = restrictions.get(i); + /** + * Accepts all edges that are either forward or backward for the given flag encoder. + * Edges where neither one of the flags is enabled will still not be accepted. If you need to retrieve all edges + * regardless of their encoding use {@link EdgeFilter#ALL_EDGES} instead. + */ + public static ConditionalAccessEdgeFilter allEdges(BooleanEncodedValue accessEnc, BooleanEncodedValue conditionalEnc) { + return new ConditionalAccessEdgeFilter(accessEnc, conditionalEnc, true, true, DEFAULT_FILTER_ID); + } - matchValue = "yes".equals(restriction.getValue()); + public static ConditionalAccessEdgeFilter outEdges(FlagEncoder flagEncoder) { + return new ConditionalAccessEdgeFilter(flagEncoder, true, false, DEFAULT_FILTER_ID); + } - List conditions = restriction.getConditions(); + public static ConditionalAccessEdgeFilter inEdges(FlagEncoder flagEncoder) { + return new ConditionalAccessEdgeFilter(flagEncoder, false, true, DEFAULT_FILTER_ID); + } - // stop as soon as time matches the combined conditions - if (TimeDependentConditionalEvaluator.match(conditions, zonedDateTime)) - return matchValue; - } + public static ConditionalAccessEdgeFilter allEdges(FlagEncoder flagEncoder) { + return new ConditionalAccessEdgeFilter(flagEncoder, true, true, DEFAULT_FILTER_ID); + } - // no restrictions with matching conditions found - return !matchValue; + public ConditionalAccessEdgeFilter setFilterId(int filterId) { + this.filterId = filterId; + return this; + } - } catch (ch.poole.conditionalrestrictionparser.ParseException e) { - //nop - } + public BooleanEncodedValue getAccessEnc() { + return accessEnc; + } - return false; + @Override + public final boolean accept(EdgeIteratorState iter) { + return fwd && iter.get(accessEnc) || bwd && iter.getReverse(accessEnc) || fwd && iter.get(conditionalEnc) || bwd && iter.getReverse(conditionalEnc); } - public boolean acceptsBackward() { - return bwd; + @Override + public String toString() { + return accessEnc.toString() + ", " + conditionalEnc.toString() + ", bwd:" + bwd + ", fwd:" + fwd; } - public boolean acceptsForward() { - return fwd; + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ConditionalAccessEdgeFilter that = (ConditionalAccessEdgeFilter) o; + + if (bwd != that.bwd) return false; + if (fwd != that.fwd) return false; + if (filterId != that.filterId) return false; + return accessEnc.equals(that.accessEnc) && conditionalEnc.equals(that.conditionalEnc); } @Override - public String toString() { - return conditionalEnc + ", bwd:" + bwd + ", fwd:" + fwd; + public int hashCode() { + int result = (bwd ? 1 : 0); + result = 31 * result + (fwd ? 1 : 0); + result = 31 * result + accessEnc.hashCode(); + result = 31 * result + conditionalEnc.hashCode(); + result = 31 * result + filterId; + return result; } } 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 9ab5c042f2b..b4664e569a2 100644 --- a/core/src/main/java/com/graphhopper/routing/util/EncodingManager.java +++ b/core/src/main/java/com/graphhopper/routing/util/EncodingManager.java @@ -446,7 +446,7 @@ public boolean acceptWay(ReaderWay way, AcceptWay acceptWay) { for (AbstractFlagEncoder encoder : edgeEncoders) { acceptWay.put(encoder.toString(), encoder.getAccess(way)); } - return acceptWay.hasAccepted() || acceptWay.hasConditional(); + return acceptWay.hasAccepted(); } public static class AcceptWay { @@ -470,7 +470,7 @@ public AcceptWay put(String key, Access access) { accessMap.put(key, access); if (access != Access.CAN_SKIP) hasAccepted = true; - if (access == Access.CONDITIONAL) + if (access.isConditional()) hasConditional = true; return this; } @@ -503,7 +503,7 @@ public boolean hasConditional () { } public enum Access { - WAY, FERRY, OTHER, CAN_SKIP, CONDITIONAL; + WAY, FERRY, OTHER, CAN_SKIP, PERMITTED, RESTRICTED; public boolean isFerry() { return this.ordinal() == FERRY.ordinal(); @@ -521,8 +521,16 @@ public boolean canSkip() { return this.ordinal() == CAN_SKIP.ordinal(); } + public boolean isPermitted() { + return this.ordinal() == PERMITTED.ordinal(); + } + + public boolean isRestricted() { + return this.ordinal() == RESTRICTED.ordinal(); + } + public boolean isConditional() { - return this.ordinal() == CONDITIONAL.ordinal(); + return isRestricted() || isPermitted(); } } diff --git a/core/src/main/java/com/graphhopper/routing/util/TimeDependentAccessEdgeFilter.java b/core/src/main/java/com/graphhopper/routing/util/TimeDependentAccessEdgeFilter.java new file mode 100644 index 00000000000..7da00e5ed3f --- /dev/null +++ b/core/src/main/java/com/graphhopper/routing/util/TimeDependentAccessEdgeFilter.java @@ -0,0 +1,94 @@ +package com.graphhopper.routing.util; + +import ch.poole.conditionalrestrictionparser.Condition; +import ch.poole.conditionalrestrictionparser.ConditionalRestrictionParser; +import ch.poole.conditionalrestrictionparser.Restriction; +import com.graphhopper.routing.EdgeKeys; +import com.graphhopper.routing.profiles.BooleanEncodedValue; +import com.graphhopper.util.DateTimeHelper; +import com.graphhopper.storage.ConditionalEdgesMap; +import com.graphhopper.storage.GraphHopperStorage; +import com.graphhopper.util.EdgeIteratorState; + +import java.io.ByteArrayInputStream; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + * Filter out temporarily blocked edges + * + * @author Andrzej Oles + */ +public class TimeDependentAccessEdgeFilter implements TimeDependentEdgeFilter { + private final BooleanEncodedValue conditionalEnc; + private final ConditionalEdgesMap conditionalEdges; + private final boolean fwd; + private final boolean bwd; + private final DateTimeHelper dateTimeHelper; + + public TimeDependentAccessEdgeFilter(GraphHopperStorage graph, FlagEncoder encoder) { + this(graph, encoder.toString()); + } + + public TimeDependentAccessEdgeFilter(GraphHopperStorage graph, String encoderName) { + this(graph, encoderName, true, true); + } + + TimeDependentAccessEdgeFilter(GraphHopperStorage graph, String encoderName, boolean fwd, boolean bwd) { + EncodingManager encodingManager = graph.getEncodingManager(); + conditionalEnc = encodingManager.getBooleanEncodedValue(EncodingManager.getKey(encoderName, "conditional_access")); + conditionalEdges = graph.getConditionalAccess(encoderName); + this.fwd = fwd; + this.bwd = bwd; + this.dateTimeHelper = new DateTimeHelper(graph); + } + + @Override + public final boolean accept(EdgeIteratorState iter, long time) { + if (fwd && iter.get(conditionalEnc) || bwd && iter.getReverse(conditionalEnc)) { + int edgeId = EdgeKeys.getOriginalEdge(iter); + // for now the filter is used only in the context of fwd search so only edges going out of the base node are explored + ZonedDateTime zonedDateTime = (time == -1) ? null : dateTimeHelper.getZonedDateTime(iter, time); + String value = conditionalEdges.getValue(edgeId); + return accept(value, zonedDateTime); + } + return true; + } + + boolean accept(String conditional, ZonedDateTime zonedDateTime) { + boolean matchValue = false; + + try { + ConditionalRestrictionParser crparser = new ConditionalRestrictionParser(new ByteArrayInputStream(conditional.getBytes())); + + ArrayList restrictions = crparser.restrictions(); + + // iterate over restrictions starting from the last one in order to match to the most specific one + for (int i = restrictions.size() - 1 ; i >= 0; i--) { + Restriction restriction = restrictions.get(i); + + matchValue = "yes".equals(restriction.getValue()); + + List conditions = restriction.getConditions(); + + // stop as soon as time matches the combined conditions + if (TimeDependentConditionalEvaluator.match(conditions, zonedDateTime)) + return matchValue; + } + + // no restrictions with matching conditions found + return !matchValue; + + } catch (ch.poole.conditionalrestrictionparser.ParseException e) { + //nop + } + + return false; + } + + @Override + public String toString() { + return conditionalEnc + ", bwd:" + bwd + ", fwd:" + fwd; + } +} diff --git a/core/src/main/java/com/graphhopper/routing/util/TimeDependentConditionalEvaluator.java b/core/src/main/java/com/graphhopper/routing/util/TimeDependentConditionalEvaluator.java index 7421333c99e..2a10e25356a 100644 --- a/core/src/main/java/com/graphhopper/routing/util/TimeDependentConditionalEvaluator.java +++ b/core/src/main/java/com/graphhopper/routing/util/TimeDependentConditionalEvaluator.java @@ -2,6 +2,8 @@ import ch.poole.conditionalrestrictionparser.Condition; import ch.poole.openinghoursparser.*; +import com.graphhopper.reader.osm.conditional.ConditionalValueParser; +import com.graphhopper.reader.osm.conditional.DateRangeParser; import java.io.ByteArrayInputStream; import java.time.ZonedDateTime; @@ -15,10 +17,18 @@ public class TimeDependentConditionalEvaluator { public static boolean match(List conditions, ZonedDateTime zonedDateTime) { for (Condition condition : conditions) { try { - OpeningHoursParser parser = new OpeningHoursParser(new ByteArrayInputStream(condition.toString().getBytes())); - List rules = parser.rules(false); + boolean matched; + if (zonedDateTime==null) { + DateRangeParser dateRangeParser = new DateRangeParser(); + matched = dateRangeParser.checkCondition(condition)==ConditionalValueParser.ConditionState.TRUE; + } + else { + OpeningHoursParser parser = new OpeningHoursParser(new ByteArrayInputStream(condition.toString().getBytes())); + List rules = parser.rules(false); + matched = matchRules(rules, zonedDateTime); + } // failed to match any of the rules - if (!matchRules(rules, zonedDateTime)) + if (!matched) return false; } catch (Exception e) { return false; diff --git a/core/src/main/java/com/graphhopper/routing/weighting/TimeDependentAccessWeighting.java b/core/src/main/java/com/graphhopper/routing/weighting/TimeDependentAccessWeighting.java index 71722101a4a..e90edb1d34b 100644 --- a/core/src/main/java/com/graphhopper/routing/weighting/TimeDependentAccessWeighting.java +++ b/core/src/main/java/com/graphhopper/routing/weighting/TimeDependentAccessWeighting.java @@ -17,7 +17,7 @@ */ package com.graphhopper.routing.weighting; -import com.graphhopper.routing.util.ConditionalAccessEdgeFilter; +import com.graphhopper.routing.util.TimeDependentAccessEdgeFilter; import com.graphhopper.routing.util.FlagEncoder; import com.graphhopper.routing.util.HintsMap; import com.graphhopper.storage.GraphHopperStorage; @@ -31,11 +31,11 @@ * @author Andrzej Oles */ public class TimeDependentAccessWeighting extends AbstractAdjustedWeighting { - private ConditionalAccessEdgeFilter edgeFilter; + private TimeDependentAccessEdgeFilter edgeFilter; public TimeDependentAccessWeighting(Weighting weighting, GraphHopperStorage graph, FlagEncoder encoder) { super(weighting); - this.edgeFilter = new ConditionalAccessEdgeFilter(graph, encoder); + this.edgeFilter = new TimeDependentAccessEdgeFilter(graph, encoder); } @Override diff --git a/core/src/test/java/com/graphhopper/reader/osm/conditional/ConditionalOSMSpeedInspectorTest.java b/core/src/test/java/com/graphhopper/reader/osm/conditional/ConditionalOSMSpeedInspectorTest.java index 6e84f908edd..6e6e47841ec 100644 --- a/core/src/test/java/com/graphhopper/reader/osm/conditional/ConditionalOSMSpeedInspectorTest.java +++ b/core/src/test/java/com/graphhopper/reader/osm/conditional/ConditionalOSMSpeedInspectorTest.java @@ -20,7 +20,6 @@ import com.graphhopper.reader.ReaderWay; import org.junit.Test; -import java.text.ParseException; import java.util.*; import static org.junit.Assert.*; @@ -28,7 +27,7 @@ /** * @author Andrzej Oles */ -public class ConditionalOSMSpeedInspectorTest extends CalendarBasedTest { +public class ConditionalOSMSpeedInspectorTest { private static List getSampleConditionalTags() { List conditionalTags = new ArrayList<>(); @@ -49,16 +48,29 @@ public void testNotConditional() { ReaderWay way = new ReaderWay(1); way.setTag("maxspeed:hgv", "80"); assertFalse(acceptor.hasConditionalSpeed(way)); - assertFalse(acceptor.isConditionLazyEvaluated()); + assertFalse(acceptor.hasLazyEvaluatedConditions()); } @Test public void testConditionalTime() { ConditionalOSMSpeedInspector acceptor = getConditionalSpeedInspector(); ReaderWay way = new ReaderWay(1); - way.setTag("maxspeed:conditional", "60 @ (23:00-05:00)"); + String tagValue = "60 @ (23:00-05:00)"; + way.setTag("maxspeed:conditional", tagValue); assertTrue(acceptor.hasConditionalSpeed(way)); - assertTrue(acceptor.isConditionLazyEvaluated()); + assertTrue(acceptor.hasLazyEvaluatedConditions()); + assertEquals(tagValue, acceptor.getTagValue()); + } + + @Test + public void testMultipleTimes() { + ConditionalOSMSpeedInspector acceptor = getConditionalSpeedInspector(); + ReaderWay way = new ReaderWay(1); + String tagValue = "50 @ (05:00-23:00); 60 @ (23:00-05:00)"; + way.setTag("maxspeed:conditional", tagValue); + assertTrue(acceptor.hasConditionalSpeed(way)); + assertTrue(acceptor.hasLazyEvaluatedConditions()); + assertEquals(tagValue, acceptor.getTagValue()); } @Test @@ -67,7 +79,7 @@ public void testConditionalWeather() { ReaderWay way = new ReaderWay(1); way.setTag("maxspeed:conditional", "60 @ snow"); assertFalse(acceptor.hasConditionalSpeed(way)); - assertFalse(acceptor.isConditionLazyEvaluated()); + assertFalse(acceptor.hasLazyEvaluatedConditions()); } @Test @@ -76,37 +88,50 @@ public void testConditionalWeight() { ReaderWay way = new ReaderWay(1); way.setTag("maxspeed:conditional", "90 @ (weight>7.5)"); assertFalse(acceptor.hasConditionalSpeed(way)); - assertFalse(acceptor.isConditionLazyEvaluated()); + acceptor.addValueParser(ConditionalParser.createNumberParser("weight", 3.5)); + assertFalse(acceptor.hasConditionalSpeed(way)); + assertFalse(acceptor.hasLazyEvaluatedConditions()); + } + + @Test + public void testConditionalWeightApplies() { + ConditionalOSMSpeedInspector acceptor = getConditionalSpeedInspector(); + ReaderWay way = new ReaderWay(1); + way.setTag("maxspeed:conditional", "90 @ (weight>7.5)"); + assertFalse(acceptor.hasConditionalSpeed(way)); acceptor.addValueParser(ConditionalParser.createNumberParser("weight", 10)); assertTrue(acceptor.hasConditionalSpeed(way)); - assertFalse(acceptor.isConditionLazyEvaluated()); + assertFalse(acceptor.hasLazyEvaluatedConditions()); + assertEquals("90", acceptor.getTagValue()); } @Test - public void testMultipleConditions() { + public void testMultipleWeights() { ConditionalOSMSpeedInspector acceptor = getConditionalSpeedInspector(); ReaderWay way = new ReaderWay(1); way.setTag("maxspeed:hgv:conditional", "90 @ (weight<=3.5); 70 @ (weight>3.5)"); assertFalse(acceptor.hasConditionalSpeed(way)); - assertFalse(acceptor.isConditionLazyEvaluated()); + acceptor.addValueParser(ConditionalParser.createNumberParser("weight", 3)); + assertTrue(acceptor.hasConditionalSpeed(way)); + assertFalse(acceptor.hasLazyEvaluatedConditions()); + assertEquals("90", acceptor.getTagValue()); acceptor.addValueParser(ConditionalParser.createNumberParser("weight", 10)); assertTrue(acceptor.hasConditionalSpeed(way)); - assertFalse(acceptor.isConditionLazyEvaluated()); - //test for value - assertEquals(acceptor.getTagValue(), "70"); - + assertFalse(acceptor.hasLazyEvaluatedConditions()); + assertEquals("70", acceptor.getTagValue()); } @Test - public void testCombinedCondition() throws ParseException { + public void testCombinedTimeWeight() { ConditionalOSMSpeedInspector acceptor = getConditionalSpeedInspector(); ReaderWay way = new ReaderWay(1); way.setTag("maxspeed:hgv:conditional", "60 @ (22:00-05:00 AND weight>7.5)"); assertFalse(acceptor.hasConditionalSpeed(way)); - assertFalse(acceptor.isConditionLazyEvaluated()); acceptor.addValueParser(ConditionalParser.createNumberParser("weight", 10)); assertTrue(acceptor.hasConditionalSpeed(way)); - assertTrue(acceptor.isConditionLazyEvaluated()); + assertTrue(acceptor.hasLazyEvaluatedConditions()); assertEquals(acceptor.getTagValue(), "60 @ (22:00-05:00)"); + acceptor.addValueParser(ConditionalParser.createNumberParser("weight", 3)); + assertFalse(acceptor.hasConditionalSpeed(way)); } } diff --git a/core/src/test/java/com/graphhopper/reader/osm/conditional/ConditionalOSMTagInspectorTest.java b/core/src/test/java/com/graphhopper/reader/osm/conditional/ConditionalOSMTagInspectorTest.java index 846cd76fd74..f507fa97eb0 100644 --- a/core/src/test/java/com/graphhopper/reader/osm/conditional/ConditionalOSMTagInspectorTest.java +++ b/core/src/test/java/com/graphhopper/reader/osm/conditional/ConditionalOSMTagInspectorTest.java @@ -20,7 +20,6 @@ import com.graphhopper.reader.ReaderWay; import org.junit.Test; -import java.text.ParseException; import java.util.*; import static org.junit.Assert.assertFalse; @@ -98,15 +97,6 @@ public void testConditionalAllowance() { assertTrue(acceptor.isRestrictedWayConditionallyPermitted(way)); } - @Test - public void testConditionalAllowanceReject() { - ConditionalOSMTagInspector acceptor = getConditionalTagInspector(); - acceptor.addValueParser(new DateRangeParser(getCalendar(2014, Calendar.MARCH, 10))); - ReaderWay way = new ReaderWay(1); - way.setTag("vehicle:conditional", "no @ (Mar 10-Aug 14)"); - assertTrue(acceptor.isPermittedWayConditionallyRestricted(way)); - } - @Test public void testConditionalSingleDay() { ConditionalOSMTagInspector acceptor = getConditionalTagInspector(); @@ -126,14 +116,37 @@ public void testConditionalAllowanceSingleDay() { } @Test - public void testCombinedCondition() throws ParseException { - String str = "no @ (10:00-18:00 AND length>5)"; + public void testConditionalAccessHours() { ConditionalOSMTagInspector acceptor = getConditionalTagInspector(); + acceptor.addValueParser(new DateRangeParser(getCalendar(2015, Calendar.DECEMBER, 27))); + ReaderWay way = new ReaderWay(1); + way.setTag("vehicle:conditional", "no @ (10:00-18:00)"); + assertFalse(acceptor.isPermittedWayConditionallyRestricted(way)); acceptor.addValueParser(ConditionalParser.createDateTimeParser()); + assertFalse(acceptor.isPermittedWayConditionallyRestricted(way)); + } + + @Test + public void testConditionalAccessLength() { + ConditionalOSMTagInspector acceptor = getConditionalTagInspector(); + acceptor.addValueParser(new DateRangeParser(getCalendar(2015, Calendar.DECEMBER, 27))); ReaderWay way = new ReaderWay(1); - way.setTag("vehicle:conditional", "no @ (10:00-18:00 AND length>5)"); + way.setTag("vehicle:conditional", "no @ length>5"); assertFalse(acceptor.isPermittedWayConditionallyRestricted(way)); acceptor.addValueParser(ConditionalParser.createNumberParser("length", 10)); assertTrue(acceptor.isPermittedWayConditionallyRestricted(way)); } + + @Test + public void testCombinedConditionHoursAndLength() { + ConditionalOSMTagInspector acceptor = getConditionalTagInspector(); + acceptor.addValueParser(new DateRangeParser(getCalendar(2015, Calendar.DECEMBER, 27))); + ReaderWay way = new ReaderWay(1); + way.setTag("vehicle:conditional", "no @ (10:00-18:00 AND length>5)"); + assertFalse(acceptor.isPermittedWayConditionallyRestricted(way)); + acceptor.addValueParser(ConditionalParser.createDateTimeParser()); + assertFalse(acceptor.isPermittedWayConditionallyRestricted(way)); + acceptor.addValueParser(ConditionalParser.createNumberParser("length", 10)); + assertFalse(acceptor.isPermittedWayConditionallyRestricted(way)); + } } diff --git a/core/src/test/java/com/graphhopper/reader/osm/conditional/ConditionalParserTest.java b/core/src/test/java/com/graphhopper/reader/osm/conditional/ConditionalParserTest.java index 9a71aa63f4c..2df78dc42d3 100644 --- a/core/src/test/java/com/graphhopper/reader/osm/conditional/ConditionalParserTest.java +++ b/core/src/test/java/com/graphhopper/reader/osm/conditional/ConditionalParserTest.java @@ -17,7 +17,6 @@ */ package com.graphhopper.reader.osm.conditional; -import org.junit.Before; import org.junit.Test; import java.text.ParseException; @@ -52,23 +51,23 @@ ConditionalParser createParser(Calendar date) { @Test public void testParseConditional() throws ParseException { String str = "no @ (2015 Sep 1-2015 Sep 30)"; - assertFalse(createParser(getCalendar(2015, Calendar.AUGUST, 31)).checkCondition(str)); - assertTrue(createParser(getCalendar(2015, Calendar.SEPTEMBER, 30)).checkCondition(str)); + assertFalse(createParser(getCalendar(2015, Calendar.AUGUST, 31)).checkCondition(str).isCheckPassed()); + assertTrue(createParser(getCalendar(2015, Calendar.SEPTEMBER, 30)).checkCondition(str).isCheckPassed()); } @Test public void testParseAllowingCondition() throws ParseException { assertFalse(createParser(getCalendar(2015, Calendar.JANUARY, 12)). - checkCondition("yes @ (2015 Sep 1-2015 Sep 30)")); + checkCondition("yes @ (2015 Sep 1-2015 Sep 30)").isCheckPassed()); } @Test public void testParsingOfLeading0() throws ParseException { assertTrue(createParser(getCalendar(2015, Calendar.DECEMBER, 2)). - checkCondition("no @ (01.11. - 31.03.)")); + checkCondition("no @ (01.11. - 31.03.)").isCheckPassed()); assertTrue(createParser(getCalendar(2015, Calendar.DECEMBER, 2)). - checkCondition("no @ (01.11 - 31.03)")); + checkCondition("no @ (01.11 - 31.03)").isCheckPassed()); } @Test @@ -82,48 +81,48 @@ public void testGetRange() throws Exception { set.add("no"); ConditionalParser instance = new ConditionalParser(set). setConditionalValueParser(ConditionalParser.createNumberParser("weight", 11)); - assertTrue(instance.checkCondition("no @weight>10")); + assertTrue(instance.checkCondition("no @weight>10").isCheckPassed()); instance.setConditionalValueParser(ConditionalParser.createNumberParser("weight", 10)); - assertFalse(instance.checkCondition("no @weight>10")); + assertFalse(instance.checkCondition("no @weight>10").isCheckPassed()); instance.setConditionalValueParser(ConditionalParser.createNumberParser("weight", 9)); - assertFalse(instance.checkCondition("no @weight>10")); + assertFalse(instance.checkCondition("no @weight>10").isCheckPassed()); instance.setConditionalValueParser(ConditionalParser.createNumberParser("weight", 11)); - assertFalse(instance.checkCondition("no @ weight < 10")); + assertFalse(instance.checkCondition("no @ weight < 10").isCheckPassed()); instance.setConditionalValueParser(ConditionalParser.createNumberParser("weight", 10)); - assertFalse(instance.checkCondition("no @ weight < 10")); + assertFalse(instance.checkCondition("no @ weight < 10").isCheckPassed()); instance.setConditionalValueParser(ConditionalParser.createNumberParser("weight", 9)); - assertTrue(instance.checkCondition("no @ weight < 10")); + assertTrue(instance.checkCondition("no @ weight < 10").isCheckPassed()); // equals is ignored for now (not that bad for weight) instance.setConditionalValueParser(ConditionalParser.createNumberParser("weight", 11)); - assertFalse(instance.checkCondition("no @ weight <= 10")); + assertFalse(instance.checkCondition("no @ weight <= 10").isCheckPassed()); instance.setConditionalValueParser(ConditionalParser.createNumberParser("weight", 10)); - assertFalse(instance.checkCondition("no @ weight <= 10")); + assertFalse(instance.checkCondition("no @ weight <= 10").isCheckPassed()); instance.setConditionalValueParser(ConditionalParser.createNumberParser("weight", 9)); - assertTrue(instance.checkCondition("no @ weight <= 10")); + assertTrue(instance.checkCondition("no @ weight <= 10").isCheckPassed()); instance.setConditionalValueParser(ConditionalParser.createNumberParser("weight", 11)); - assertFalse(instance.checkCondition("no @ weight<=10")); + assertFalse(instance.checkCondition("no @ weight<=10").isCheckPassed()); instance.setConditionalValueParser(ConditionalParser.createNumberParser("weight", 10)); - assertFalse(instance.checkCondition("no @ weight<=10")); + assertFalse(instance.checkCondition("no @ weight<=10").isCheckPassed()); instance.setConditionalValueParser(ConditionalParser.createNumberParser("weight", 9)); - assertTrue(instance.checkCondition("no @ weight<=10")); + assertTrue(instance.checkCondition("no @ weight<=10").isCheckPassed()); instance.setConditionalValueParser(ConditionalParser.createNumberParser("height", 1)); - assertFalse(instance.checkCondition("no @ height > 2")); + assertFalse(instance.checkCondition("no @ height > 2").isCheckPassed()); instance.setConditionalValueParser(ConditionalParser.createNumberParser("height", 2)); - assertFalse(instance.checkCondition("no @ height > 2")); + assertFalse(instance.checkCondition("no @ height > 2").isCheckPassed()); instance.setConditionalValueParser(ConditionalParser.createNumberParser("height", 3)); - assertTrue(instance.checkCondition("no @ height > 2")); + assertTrue(instance.checkCondition("no @ height > 2").isCheckPassed()); // unit is allowed according to wiki instance.setConditionalValueParser(ConditionalParser.createNumberParser("height", 1)); - assertFalse(instance.checkCondition("no @ height > 2t")); + assertFalse(instance.checkCondition("no @ height > 2t").isCheckPassed()); instance.setConditionalValueParser(ConditionalParser.createNumberParser("height", 2)); - assertFalse(instance.checkCondition("no @ height > 2t")); + assertFalse(instance.checkCondition("no @ height > 2t").isCheckPassed()); instance.setConditionalValueParser(ConditionalParser.createNumberParser("height", 3)); - assertTrue(instance.checkCondition("no @ height > 2t")); + assertTrue(instance.checkCondition("no @ height > 2t").isCheckPassed()); } @Test diff --git a/core/src/test/java/com/graphhopper/routing/util/ConditionalAccessTest.java b/core/src/test/java/com/graphhopper/routing/util/ConditionalAccessTest.java index 6d55d076d14..d0979c10841 100644 --- a/core/src/test/java/com/graphhopper/routing/util/ConditionalAccessTest.java +++ b/core/src/test/java/com/graphhopper/routing/util/ConditionalAccessTest.java @@ -18,12 +18,17 @@ package com.graphhopper.routing.util; import com.graphhopper.reader.ReaderWay; +import com.graphhopper.reader.osm.conditional.CalendarBasedTest; +import com.graphhopper.reader.osm.conditional.ConditionalOSMTagInspector; +import com.graphhopper.reader.osm.conditional.ConditionalParser; +import com.graphhopper.reader.osm.conditional.DateRangeParser; import com.graphhopper.routing.profiles.*; import com.graphhopper.storage.*; import com.graphhopper.util.EdgeIteratorState; import org.junit.Test; import java.util.ArrayList; +import java.util.Calendar; import java.util.List; import static org.junit.Assert.*; @@ -32,12 +37,23 @@ /** * @author Andrzej Oles */ -public class ConditionalAccessTest { +public class ConditionalAccessTest extends CalendarBasedTest { private static final String CONDITIONAL = "no @ (Mar 15-Jun 15)"; - private final CarFlagEncoder encoder = new CarFlagEncoder(); + private final CarFlagEncoder encoder = new TestFlagEncoder(); private final EncodingManager encodingManager = EncodingManager.create(encoder); private final GraphHopperStorage graph = new GraphBuilder(encodingManager).create(); + class TestFlagEncoder extends CarFlagEncoder { + @Override + protected void init() { + super.init(); + ConditionalOSMTagInspector conditionalTagInspector = new ConditionalOSMTagInspector(restrictions, restrictedValues, intendedValues); + conditionalTagInspector.addValueParser(new DateRangeParser(getCalendar(2014, Calendar.APRIL, 10))); + conditionalTagInspector.addValueParser(ConditionalParser.createDateTimeParser()); + setConditionalTagInspector(conditionalTagInspector); + } + } + private ReaderWay createWay() { ReaderWay way = new ReaderWay(0); way.setTag("highway", "primary"); @@ -53,6 +69,22 @@ private EdgeIteratorState createEdge(ReaderWay way) { return edge; } + @Test + public void getDefaultAccessClosed() { + ReaderWay way = createWay(); + way.setTag("access:conditional", CONDITIONAL); + BooleanEncodedValue accessEnc = encoder.getAccessEnc(); + assertFalse(createEdge(way).get(accessEnc)); + } + + @Test + public void getDefaultAccessOpen() { + ReaderWay way = createWay(); + way.setTag("access:conditional", "no @ (Apr 15-Jun 15)"); + BooleanEncodedValue accessEnc = encoder.getAccessEnc(); + assertTrue(createEdge(way).get(accessEnc)); + } + @Test public void isAccessConditional() { ReaderWay way = createWay(); diff --git a/core/src/test/java/com/graphhopper/routing/util/ConditionalAccessEdgeFilterTest.java b/core/src/test/java/com/graphhopper/routing/util/TimeDependentAccessEdgeFilterTest.java similarity index 98% rename from core/src/test/java/com/graphhopper/routing/util/ConditionalAccessEdgeFilterTest.java rename to core/src/test/java/com/graphhopper/routing/util/TimeDependentAccessEdgeFilterTest.java index 88e551def74..05d72b4baef 100644 --- a/core/src/test/java/com/graphhopper/routing/util/ConditionalAccessEdgeFilterTest.java +++ b/core/src/test/java/com/graphhopper/routing/util/TimeDependentAccessEdgeFilterTest.java @@ -37,7 +37,7 @@ /** * @author Andrzej Oles */ -public class ConditionalAccessEdgeFilterTest { +public class TimeDependentAccessEdgeFilterTest { private static final TimeZoneMap timeZoneMap = TimeZoneMap.forRegion(52, 13, 53, 14); private final CarFlagEncoder encoder = new CarFlagEncoder(); @@ -46,11 +46,11 @@ public class ConditionalAccessEdgeFilterTest { private final NodeAccess nodeAccess = graph.getNodeAccess(); private final TimeDependentEdgeFilter filter; - public ConditionalAccessEdgeFilterTest() { + public TimeDependentAccessEdgeFilterTest() { nodeAccess.setNode(0, 52, 13); nodeAccess.setNode(1, 53, 14); graph.setTimeZoneMap(timeZoneMap); - filter = new ConditionalAccessEdgeFilter(graph, encoder); + filter = new TimeDependentAccessEdgeFilter(graph, encoder); } private EdgeIteratorState createConditionalEdge(boolean closed, String conditional) { diff --git a/reader-osm/src/main/java/com/graphhopper/reader/osm/OSMReader.java b/reader-osm/src/main/java/com/graphhopper/reader/osm/OSMReader.java index 189cfa3768d..903ddac5ae3 100644 --- a/reader-osm/src/main/java/com/graphhopper/reader/osm/OSMReader.java +++ b/reader-osm/src/main/java/com/graphhopper/reader/osm/OSMReader.java @@ -464,7 +464,7 @@ protected void storeConditionalAccess(EncodingManager.AcceptWay acceptWay, List< if (acceptWay.hasConditional()) { for (FlagEncoder encoder : encodingManager.fetchEdgeEncoders()) { String encoderName = encoder.toString(); - if (acceptWay.getAccess(encoderName) == EncodingManager.Access.CONDITIONAL) { + if (acceptWay.getAccess(encoderName).isConditional()) { String value = ((AbstractFlagEncoder) encoder).getConditionalTagInspector().getTagValue(); ((GraphHopperStorage) ghStorage).getConditionalAccess(encoderName).addEdges(createdEdges, value); } @@ -479,7 +479,7 @@ protected void storeConditionalSpeed(IntsRef edgeFlags, List if (encodingManager.hasEncodedValue(encoderName) && encodingManager.getBooleanEncodedValue(encoderName).getBool(false, edgeFlags)) { ConditionalSpeedInspector conditionalSpeedInspector = ((AbstractFlagEncoder) encoder).getConditionalSpeedInspector(); - if (conditionalSpeedInspector.isConditionLazyEvaluated()) { + if (conditionalSpeedInspector.hasLazyEvaluatedConditions()) { String value = conditionalSpeedInspector.getTagValue(); ((GraphHopperStorage) ghStorage).getConditionalSpeed(encoder).addEdges(createdEdges, value); }