001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.tools; 003 004import java.awt.geom.Area; 005import java.io.IOException; 006import java.io.InputStream; 007import java.util.ArrayList; 008import java.util.Collection; 009 010import org.openstreetmap.josm.data.coor.LatLon; 011import org.openstreetmap.josm.data.osm.BBox; 012import org.openstreetmap.josm.data.osm.DataSet; 013import org.openstreetmap.josm.data.osm.Way; 014import org.openstreetmap.josm.io.CachedFile; 015import org.openstreetmap.josm.io.IllegalDataException; 016import org.openstreetmap.josm.io.OsmReader; 017import org.openstreetmap.josm.tools.GeoPropertyIndex.GeoProperty; 018import org.openstreetmap.josm.tools.Geometry.PolygonIntersection; 019 020/** 021 * Look up, if there is right- or left-hand traffic at a certain place. 022 */ 023public final class RightAndLefthandTraffic { 024 025 private static class RLTrafficGeoProperty implements GeoProperty<Boolean> { 026 027 @Override 028 public Boolean get(LatLon ll) { 029 for (Area a : leftHandTrafficPolygons) { 030 if (a.contains(ll.lon(), ll.lat())) 031 return Boolean.TRUE; 032 } 033 return Boolean.FALSE; 034 } 035 036 @Override 037 public Boolean get(BBox box) { 038 Area abox = new Area(box.toRectangle()); 039 for (Area a : leftHandTrafficPolygons) { 040 PolygonIntersection is = Geometry.polygonIntersection(abox, a, 1e-10 /* using deg and not meters */); 041 if (is == PolygonIntersection.FIRST_INSIDE_SECOND) 042 return Boolean.TRUE; 043 if (is != PolygonIntersection.OUTSIDE) 044 return null; 045 } 046 return Boolean.FALSE; 047 } 048 } 049 050 private static volatile Collection<Area> leftHandTrafficPolygons; 051 private static volatile GeoPropertyIndex<Boolean> rlCache; 052 053 private RightAndLefthandTraffic() { 054 // Hide implicit public constructor for utility classes 055 } 056 057 /** 058 * Check if there is right-hand traffic at a certain location. 059 * 060 * TODO: Synchronization can be refined inside the {@link GeoPropertyIndex} 061 * as most look-ups are read-only. 062 * @param ll the coordinates of the point 063 * @return true if there is right-hand traffic, false if there is left-hand traffic 064 */ 065 public static synchronized boolean isRightHandTraffic(LatLon ll) { 066 if (leftHandTrafficPolygons == null) { 067 initialize(); 068 } 069 return !rlCache.get(ll); 070 } 071 072 private static void initialize() { 073 leftHandTrafficPolygons = new ArrayList<>(); 074 try (CachedFile cf = new CachedFile("resource://data/left-right-hand-traffic.osm"); 075 InputStream is = cf.getInputStream()) { 076 DataSet data = OsmReader.parseDataSet(is, null); 077 for (Way w : data.getWays()) { 078 leftHandTrafficPolygons.add(Geometry.getAreaLatLon(w.getNodes())); 079 } 080 } catch (IOException | IllegalDataException ex) { 081 throw new RuntimeException(ex); 082 } 083 rlCache = new GeoPropertyIndex<>(new RLTrafficGeoProperty(), 24); 084 } 085}