
org.opentripplanner.graph_builder.module.osm.OSMSpecifier 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
package org.opentripplanner.graph_builder.module.osm;
import java.util.ArrayList;
import java.util.List;
import org.opentripplanner.common.model.P2;
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 less 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 OSMSpecifier will be applied to that way
* (2 exact matches beats 1 exact match and a wildcard match).
*/
public class OSMSpecifier {
public List> kvpairs;
public OSMSpecifier() {
kvpairs = new ArrayList>(); // TODO string-pairs with a proper OSM tag class
}
public OSMSpecifier(String spec) {
this();
setKvpairs(spec);
}
public void setKvpairs(String spec) {
String[] pairs = spec.split(";");
for (String pair : pairs) {
String[] kv = pair.split("=");
kvpairs.add(new P2(kv[0], kv[1]));
}
}
/**
* Calculates a pair of scores expressing how well an OSM entity's tags match this specifier.
*
* Tags in this specifier are matched against those for the left and right side of the OSM way separately. See:
* http://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right
* TODO: we should probably support forward/backward as well.
* TODO: simply count the number of full, partial, and wildcard matches instead of using a scoring system.
*
* @param match an OSM tagged object to compare to this specifier
*/
public P2 matchScores(OSMWithTags match) {
int leftScore = 0, rightScore = 0;
int leftMatches = 0, rightMatches = 0;
for (P2 pair : kvpairs) {
// TODO why are we repeatedly converting these to lower case every time they are used?
// Probably because it used to be possible to set them from Spring XML.
String tag = pair.first.toLowerCase();
String value = pair.second.toLowerCase();
String leftMatchValue = match.getTag(tag + ":left");
String rightMatchValue = match.getTag(tag + ":right");
String matchValue = match.getTag(tag);
if (leftMatchValue == null) {
leftMatchValue = matchValue;
}
if (rightMatchValue == null) {
rightMatchValue = matchValue;
}
int leftTagScore = getTagScore(value, leftMatchValue);
leftScore += leftTagScore;
if (leftTagScore > 0) {
leftMatches ++;
}
int rightTagScore = getTagScore(value, rightMatchValue);
rightScore += rightTagScore;
if (rightTagScore > 0) {
rightMatches ++;
}
}
int allMatchLeftBonus = (leftMatches == kvpairs.size()) ? 10 : 0;
leftScore += allMatchLeftBonus;
int allMatchRightBonus = (rightMatches == kvpairs.size()) ? 10 : 0;
rightScore += allMatchRightBonus;
P2 score = new P2(leftScore, rightScore);
return score;
}
/**
* Calculates a score expressing how well an OSM entity's tags match this specifier.
* This does exactly the same thing as matchScores but without regard for :left and :right.
*/
public int matchScore(OSMWithTags match) {
int score = 0;
int matches = 0;
for (P2 pair : kvpairs) {
String tag = pair.first.toLowerCase();
String value = pair.second.toLowerCase();
String matchValue = match.getTag(tag);
int tagScore = getTagScore(value, matchValue);
score += tagScore;
if (tagScore > 0) {
matches += 1;
}
}
score += matches == kvpairs.size() ? 10 : 0;
return score;
}
/**
* 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 int getTagScore(String value, String matchValue) {
// either this matches on a wildcard, or it matches exactly
if (value.equals("*") && matchValue != null) {
return 1; // wildcard matches are basically tiebreakers
} else if (value.equals(matchValue)) {
return 100;
} else {
if (value.contains(":")) {
// treat cases like cobblestone:flattened as cobblestone if a more-specific match
// does not apply
value = value.split(":", 2)[0];
if (value.equals(matchValue)) {
return 75;
} else {
return 0;
}
} else {
return 0;
}
}
}
public void addTag(String key, String value) {
kvpairs.add(new P2(key, value));
}
public String toString() {
StringBuilder builder = new StringBuilder();
for (P2 pair : kvpairs) {
builder.append(pair.first);
builder.append("=");
builder.append(pair.second);
builder.append(";");
}
builder.deleteCharAt(builder.length() - 1); // remove trailing semicolon
return builder.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy