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