
org.opentripplanner.openstreetmap.wayproperty.specifier.BestMatchSpecifier Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of otp Show documentation
Show all versions of otp Show documentation
The OpenTripPlanner multimodal journey planning system
The newest version!
package org.opentripplanner.openstreetmap.wayproperty.specifier;
import java.util.Arrays;
import java.util.stream.Collectors;
import org.opentripplanner.framework.tostring.ToStringBuilder;
import org.opentripplanner.openstreetmap.model.OSMWithTags;
/**
* Specifies a class of OSM tagged entities (e.g. ways) by a list of tags and their values (which
* may be wildcards). The OSMSpecifier which matches the most tags on an OSM entity will win. In the
* event that several OSMSpecifiers match the same number of tags, the one that does so using fewer
* wildcards will win. For example, if one OSMSpecifier has the tags (highway=residential,
* cycleway=*) and another has (highway=residential, surface=paved) and a way has the tags
* (highway=residential, cycleway=lane, surface=paved) the second specifier will be applied to that
* way (2 exact matches beats 1 exact match and a wildcard match).
*/
public class BestMatchSpecifier implements OsmSpecifier {
/**
* If a tag matches completely (both key and value match) this is the score returned for it.
*
* @see ExactMatchSpecifier#MATCH_MULTIPLIER
*/
public static final int EXACT_MATCH_SCORE = 100;
public static final int WILDCARD_MATCH_SCORE = 1;
public static final int NO_MATCH_SCORE = 0;
private final Condition[] conditions;
public BestMatchSpecifier(String spec) {
conditions = OsmSpecifier.parseConditions(spec, ";");
}
@Override
public Scores matchScores(OSMWithTags way) {
int backwardScore = 0, forwardScore = 0;
int backwardMatches = 0, forwardMatches = 0;
for (var test : conditions) {
var forwardMatch = test.matchForward(way);
var backwardMatch = test.matchBackward(way);
int backwardTagScore = toTagScore(backwardMatch);
backwardScore += backwardTagScore;
if (backwardTagScore > 0) {
backwardMatches++;
}
int forwardTagScore = toTagScore(forwardMatch);
forwardScore += forwardTagScore;
if (forwardTagScore > 0) {
forwardMatches++;
}
}
int allMatchBackwardBonus = (backwardMatches == conditions.length) ? 10 : 0;
backwardScore += allMatchBackwardBonus;
int allMatchForwardBonus = (forwardMatches == conditions.length) ? 10 : 0;
forwardScore += allMatchForwardBonus;
return new Scores(forwardScore, backwardScore);
}
@Override
public int matchScore(OSMWithTags way) {
int score = 0;
int matches = 0;
for (var test : conditions) {
var matchValue = test.match(way);
int tagScore = toTagScore(matchValue);
score += tagScore;
if (tagScore > 0) {
matches += 1;
}
}
score += matches == conditions.length ? 10 : 0;
return score;
}
@Override
public String toDocString() {
return Arrays.stream(conditions).map(Object::toString).collect(Collectors.joining("; "));
}
@Override
public String toString() {
return ToStringBuilder.of(this.getClass()).addObj("conditions", conditions).toString();
}
/**
* Calculates a score indicating how well an OSM tag value matches the given matchValue. An exact
* match is worth 100 points, a partial match on the part of the value before a colon is worth 75
* points, and a wildcard match is worth only one point, to serve as a tiebreaker. A score of 0
* means they do not match.
*/
private static int toTagScore(Condition.MatchResult res) {
return switch (res) {
case EXACT -> EXACT_MATCH_SCORE;
// wildcard matches are basically tiebreakers
case WILDCARD -> WILDCARD_MATCH_SCORE;
// no match means no score
case NONE -> NO_MATCH_SCORE;
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy