[7193] | 1 | // License: GPL. For details, see LICENSE file.
|
---|
| 2 | package org.openstreetmap.josm.tools;
|
---|
| 3 |
|
---|
| 4 | import java.util.Collection;
|
---|
[11247] | 5 | import java.util.Collections;
|
---|
| 6 | import java.util.Set;
|
---|
[8126] | 7 |
|
---|
[7193] | 8 | import org.openstreetmap.josm.data.coor.LatLon;
|
---|
[11247] | 9 | import org.openstreetmap.josm.data.osm.OsmPrimitive;
|
---|
| 10 | import org.openstreetmap.josm.data.osm.Relation;
|
---|
| 11 | import org.openstreetmap.josm.data.osm.RelationMember;
|
---|
[7193] | 12 | import org.openstreetmap.josm.data.osm.Way;
|
---|
| 13 |
|
---|
| 14 | /**
|
---|
| 15 | * Look up, if there is right- or left-hand traffic at a certain place.
|
---|
[14032] | 16 | * See <a href="https://en.wikipedia.org/wiki/Left-_and_right-hand_traffic">Left- and right-hand traffic</a>
|
---|
[7193] | 17 | */
|
---|
[8514] | 18 | public final class RightAndLefthandTraffic {
|
---|
[7509] | 19 |
|
---|
[11256] | 20 | private static final String DRIVING_SIDE = "driving_side";
|
---|
| 21 | private static final String LEFT = "left";
|
---|
| 22 | private static final String RIGHT = "right";
|
---|
| 23 |
|
---|
[11264] | 24 | private static volatile GeoPropertyIndex<Boolean> rlCache;
|
---|
[7193] | 25 |
|
---|
[8487] | 26 | private RightAndLefthandTraffic() {
|
---|
| 27 | // Hide implicit public constructor for utility classes
|
---|
| 28 | }
|
---|
| 29 |
|
---|
[7193] | 30 | /**
|
---|
| 31 | * Check if there is right-hand traffic at a certain location.
|
---|
[7509] | 32 | *
|
---|
[7193] | 33 | * @param ll the coordinates of the point
|
---|
| 34 | * @return true if there is right-hand traffic, false if there is left-hand traffic
|
---|
| 35 | */
|
---|
| 36 | public static synchronized boolean isRightHandTraffic(LatLon ll) {
|
---|
[14032] | 37 | Boolean value = rlCache.get(ll);
|
---|
| 38 | return value == null || !value;
|
---|
[7193] | 39 | }
|
---|
| 40 |
|
---|
[11247] | 41 | /**
|
---|
| 42 | * Initializes Right and lefthand traffic data.
|
---|
[16321] | 43 | * @param geoProperty the property containing the traffic data
|
---|
[11247] | 44 | * TODO: Synchronization can be refined inside the {@link GeoPropertyIndex} as most look-ups are read-only.
|
---|
| 45 | */
|
---|
[16321] | 46 | static synchronized void initialize(DefaultGeoProperty geoProperty) {
|
---|
| 47 | rlCache = new GeoPropertyIndex<>(geoProperty, 24);
|
---|
[11247] | 48 | }
|
---|
| 49 |
|
---|
[16321] | 50 | static void appendLeftDrivingBoundaries(OsmPrimitive osm, Collection<Way> ways) {
|
---|
[11247] | 51 | // Find all outer ways of left-driving countries. Many of them are adjacent (African and Asian states)
|
---|
[16321] | 52 | if (LEFT.equals(osm.get(DRIVING_SIDE))) {
|
---|
| 53 | if (osm instanceof Way) {
|
---|
| 54 | Way w = (Way) osm;
|
---|
[11247] | 55 | addWayIfNotInner(ways, w);
|
---|
[16321] | 56 | } else if (osm instanceof Relation && osm.isMultipolygon()) {
|
---|
| 57 | Relation r = (Relation) osm;
|
---|
[11247] | 58 | for (RelationMember rm : r.getMembers()) {
|
---|
[11256] | 59 | if (rm.isWay() && "outer".equals(rm.getRole()) && !RIGHT.equals(rm.getMember().get(DRIVING_SIDE))) {
|
---|
[11247] | 60 | addWayIfNotInner(ways, (Way) rm.getMember());
|
---|
| 61 | }
|
---|
| 62 | }
|
---|
| 63 | }
|
---|
| 64 | }
|
---|
| 65 | }
|
---|
| 66 |
|
---|
| 67 | /**
|
---|
| 68 | * Adds w to ways, except if it is an inner way of another lefthand driving multipolygon,
|
---|
| 69 | * as Lesotho in South Africa and Cyprus village in British Cyprus base.
|
---|
| 70 | * @param ways ways
|
---|
| 71 | * @param w way
|
---|
| 72 | */
|
---|
| 73 | private static void addWayIfNotInner(Collection<Way> ways, Way w) {
|
---|
| 74 | Set<Way> s = Collections.singleton(w);
|
---|
| 75 | for (Relation r : OsmPrimitive.getParentRelations(s)) {
|
---|
[11256] | 76 | if (r.isMultipolygon() && LEFT.equals(r.get(DRIVING_SIDE)) &&
|
---|
[11247] | 77 | "inner".equals(r.getMembersFor(s).iterator().next().getRole())) {
|
---|
[12620] | 78 | if (Logging.isDebugEnabled()) {
|
---|
| 79 | Logging.debug("Skipping {0} because inner part of {1}", w.get("name:en"), r.get("name:en"));
|
---|
[11247] | 80 | }
|
---|
| 81 | return;
|
---|
| 82 | }
|
---|
| 83 | }
|
---|
| 84 | ways.add(w);
|
---|
| 85 | }
|
---|
[7193] | 86 | }
|
---|