Changeset 11247 in josm for trunk/src/org/openstreetmap/josm/tools/RightAndLefthandTraffic.java
- Timestamp:
- 2016-11-13T00:29:31+01:00 (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/tools/RightAndLefthandTraffic.java
r9639 r11247 3 3 4 4 import java.awt.geom.Area; 5 import java.io.File; 6 import java.io.FileInputStream; 7 import java.io.FileOutputStream; 5 8 import java.io.IOException; 6 9 import java.io.InputStream; 10 import java.io.OutputStreamWriter; 11 import java.io.PrintWriter; 12 import java.io.Writer; 13 import java.nio.charset.StandardCharsets; 7 14 import java.util.ArrayList; 8 15 import java.util.Collection; 9 16 import java.util.Collections; 17 import java.util.List; 18 import java.util.Set; 19 20 import org.openstreetmap.josm.Main; 21 import org.openstreetmap.josm.actions.JoinAreasAction; 22 import org.openstreetmap.josm.actions.JoinAreasAction.JoinAreasResult; 23 import org.openstreetmap.josm.actions.JoinAreasAction.Multipolygon; 24 import org.openstreetmap.josm.actions.PurgeAction; 10 25 import org.openstreetmap.josm.data.coor.LatLon; 11 26 import org.openstreetmap.josm.data.osm.BBox; 12 27 import org.openstreetmap.josm.data.osm.DataSet; 28 import org.openstreetmap.josm.data.osm.OsmPrimitive; 29 import org.openstreetmap.josm.data.osm.Relation; 30 import org.openstreetmap.josm.data.osm.RelationMember; 13 31 import org.openstreetmap.josm.data.osm.Way; 14 import org.openstreetmap.josm.io.CachedFile;15 32 import org.openstreetmap.josm.io.IllegalDataException; 16 33 import org.openstreetmap.josm.io.OsmReader; 34 import org.openstreetmap.josm.io.OsmWriter; 35 import org.openstreetmap.josm.io.OsmWriterFactory; 17 36 import org.openstreetmap.josm.tools.GeoPropertyIndex.GeoProperty; 18 37 import org.openstreetmap.josm.tools.Geometry.PolygonIntersection; … … 58 77 * Check if there is right-hand traffic at a certain location. 59 78 * 60 * TODO: Synchronization can be refined inside the {@link GeoPropertyIndex}61 * as most look-ups are read-only.62 79 * @param ll the coordinates of the point 63 80 * @return true if there is right-hand traffic, false if there is left-hand traffic 64 81 */ 65 82 public static synchronized boolean isRightHandTraffic(LatLon ll) { 66 if (leftHandTrafficPolygons == null) {67 initialize();68 }69 83 return !rlCache.get(ll); 70 84 } 71 85 72 private static void initialize() { 86 /** 87 * Initializes Right and lefthand traffic data. 88 * TODO: Synchronization can be refined inside the {@link GeoPropertyIndex} as most look-ups are read-only. 89 */ 90 public static synchronized void initialize() { 73 91 leftHandTrafficPolygons = new ArrayList<>(); 74 try (CachedFile cf = new CachedFile("resource://data/left-right-hand-traffic.osm"); 75 InputStream is = cf.getInputStream()) { 76 DataSet data = OsmReader.parseDataSet(is, null); 77 for (Way w : data.getWays()) { 78 leftHandTrafficPolygons.add(Geometry.getAreaLatLon(w.getNodes())); 79 } 80 } catch (IOException | IllegalDataException ex) { 92 Collection<Way> optimizedWays = loadOptimizedBoundaries(); 93 if (optimizedWays.isEmpty()) { 94 optimizedWays = computeOptimizedBoundaries(); 95 saveOptimizedBoundaries(optimizedWays); 96 } 97 for (Way w : optimizedWays) { 98 leftHandTrafficPolygons.add(Geometry.getAreaLatLon(w.getNodes())); 99 } 100 rlCache = new GeoPropertyIndex<>(new RLTrafficGeoProperty(), 24); 101 } 102 103 private static Collection<Way> computeOptimizedBoundaries() { 104 Collection<Way> ways = new ArrayList<>(); 105 Collection<OsmPrimitive> toPurge = new ArrayList<>(); 106 // Find all outer ways of left-driving countries. Many of them are adjacent (African and Asian states) 107 DataSet data = Territories.getDataSet(); 108 Collection<Relation> allRelations = data.getRelations(); 109 Collection<Way> allWays = data.getWays(); 110 for (Way w : allWays) { 111 if ("left".equals(w.get("driving_side"))) { 112 addWayIfNotInner(ways, w); 113 } 114 } 115 for (Relation r : allRelations) { 116 if (r.isMultipolygon() && "left".equals(r.get("driving_side"))) { 117 for (RelationMember rm : r.getMembers()) { 118 if (rm.isWay() && "outer".equals(rm.getRole())) { 119 addWayIfNotInner(ways, (Way) rm.getMember()); 120 } 121 } 122 } 123 } 124 toPurge.addAll(allRelations); 125 toPurge.addAll(allWays); 126 toPurge.removeAll(ways); 127 // Remove ways from parent relations for following optimizations 128 for (Relation r : OsmPrimitive.getParentRelations(ways)) { 129 r.setMembers(null); 130 } 131 // Remove all tags to avoid any conflict 132 for (Way w : ways) { 133 w.removeAll(); 134 } 135 // Purge all other ways and relations so dataset only contains lefthand traffic data 136 new PurgeAction().doPurge(toPurge, false); 137 // Combine adjacent countries into a single polygon 138 Collection<Way> optimizedWays = new ArrayList<>(); 139 List<Multipolygon> areas = JoinAreasAction.collectMultipolygons(ways); 140 if (areas != null) { 141 try { 142 JoinAreasResult result = new JoinAreasAction().joinAreas(areas); 143 if (result.hasChanges) { 144 for (Multipolygon mp : result.polygons) { 145 optimizedWays.add(mp.outerWay); 146 } 147 } 148 } catch (UserCancelException ex) { 149 Main.warn(ex); 150 } 151 } 152 if (optimizedWays.isEmpty()) { 153 // Problem: don't optimize 154 Main.warn("Unable to join left-driving countries polygons"); 155 optimizedWays.addAll(ways); 156 } 157 return optimizedWays; 158 } 159 160 /** 161 * Adds w to ways, except if it is an inner way of another lefthand driving multipolygon, 162 * as Lesotho in South Africa and Cyprus village in British Cyprus base. 163 * @param ways ways 164 * @param w way 165 */ 166 private static void addWayIfNotInner(Collection<Way> ways, Way w) { 167 Set<Way> s = Collections.singleton(w); 168 for (Relation r : OsmPrimitive.getParentRelations(s)) { 169 if (r.isMultipolygon() && "left".equals(r.get("driving_side")) && 170 "inner".equals(r.getMembersFor(s).iterator().next().getRole())) { 171 if (Main.isDebugEnabled()) { 172 Main.debug("Skipping " + w.get("name:en") + " because inner part of " + r.get("name:en")); 173 } 174 return; 175 } 176 } 177 ways.add(w); 178 } 179 180 private static void saveOptimizedBoundaries(Collection<Way> optimizedWays) { 181 DataSet ds = optimizedWays.iterator().next().getDataSet(); 182 File file = new File(Main.pref.getCacheDirectory(), "left-right-hand-traffic.osm"); 183 try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8); 184 OsmWriter w = OsmWriterFactory.createOsmWriter(new PrintWriter(writer), false, ds.getVersion()) 185 ) { 186 w.header(false); 187 w.writeContent(ds); 188 w.footer(); 189 } catch (IOException ex) { 81 190 throw new RuntimeException(ex); 82 191 } 83 rlCache = new GeoPropertyIndex<>(new RLTrafficGeoProperty(), 24); 192 } 193 194 private static Collection<Way> loadOptimizedBoundaries() { 195 try (InputStream is = new FileInputStream(new File(Main.pref.getCacheDirectory(), "left-right-hand-traffic.osm"))) { 196 return OsmReader.parseDataSet(is, null).getWays(); 197 } catch (IllegalDataException | IOException ex) { 198 Main.trace(ex); 199 return Collections.emptyList(); 200 } 84 201 } 85 202 }
Note:
See TracChangeset
for help on using the changeset viewer.