source: josm/trunk/src/org/openstreetmap/josm/tools/Territories.java@ 15565

Last change on this file since 15565 was 15565, checked in by Don-vip, 4 years ago

fix #18302 - support national taginfo instances

  • Property svn:eol-style set to native
File size: 5.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.IOException;
7import java.io.InputStream;
8import java.util.ArrayList;
9import java.util.Collection;
10import java.util.Collections;
11import java.util.HashMap;
12import java.util.Map;
13import java.util.Map.Entry;
14import java.util.Set;
15import java.util.TreeMap;
16import java.util.stream.Collectors;
17
18import org.openstreetmap.josm.data.coor.LatLon;
19import org.openstreetmap.josm.data.osm.DataSet;
20import org.openstreetmap.josm.data.osm.OsmPrimitive;
21import org.openstreetmap.josm.data.osm.Relation;
22import org.openstreetmap.josm.data.osm.Way;
23import org.openstreetmap.josm.io.CachedFile;
24import org.openstreetmap.josm.io.IllegalDataException;
25import org.openstreetmap.josm.io.OsmReader;
26
27/**
28 * Look up territories ISO3166 codes at a certain place.
29 */
30public final class Territories {
31
32 /** Internal OSM filename */
33 public static final String FILENAME = "boundaries.osm";
34
35 private static final String ISO3166_1 = "ISO3166-1:alpha2";
36 private static final String ISO3166_2 = "ISO3166-2";
37 private static final String TAGINFO = "taginfo";
38
39 private static DataSet dataSet;
40
41 private static volatile Map<String, GeoPropertyIndex<Boolean>> iso3166Cache;
42 private static volatile Map<String, String> taginfoCache;
43
44 private Territories() {
45 // Hide implicit public constructor for utility classes
46 }
47
48 /**
49 * Get all known ISO3166-1 and ISO3166-2 codes.
50 *
51 * @return the ISO3166-1 and ISO3166-2 codes for the given location
52 */
53 public static synchronized Set<String> getKnownIso3166Codes() {
54 return iso3166Cache.keySet();
55 }
56
57 /**
58 * Returns the {@link GeoPropertyIndex} for the given ISO3166-1 or ISO3166-2 code.
59 * @param code the ISO3166-1 or ISO3166-2 code
60 * @return the {@link GeoPropertyIndex} for the given {@code code}
61 * @since 14484
62 */
63 public static GeoPropertyIndex<Boolean> getGeoPropertyIndex(String code) {
64 return iso3166Cache.get(code);
65 }
66
67 /**
68 * Determine, if a point is inside a territory with the given ISO3166-1
69 * or ISO3166-2 code.
70 *
71 * @param code the ISO3166-1 or ISO3166-2 code
72 * @param ll the coordinates of the point
73 * @return true, if the point is inside a territory with the given code
74 */
75 public static synchronized boolean isIso3166Code(String code, LatLon ll) {
76 GeoPropertyIndex<Boolean> gpi = iso3166Cache.get(code);
77 if (gpi == null) {
78 Logging.warn(tr("Unknown territory id: {0}", code));
79 return false;
80 }
81 return Boolean.TRUE.equals(gpi.get(ll)); // avoid NPE, see #16491
82 }
83
84 /**
85 * Returns the original territories dataset. Be extra cautious when manipulating it!
86 * @return the original territories dataset
87 * @since 15565
88 */
89 public static synchronized DataSet getOriginalDataSet() {
90 return dataSet;
91 }
92
93 /**
94 * Returns a copy of the territories dataset.
95 * @return a copy of the territories dataset
96 */
97 public static synchronized DataSet getDataSet() {
98 return new DataSet(dataSet);
99 }
100
101 /**
102 * Initializes territories.
103 * TODO: Synchronization can be refined inside the {@link GeoPropertyIndex} as most look-ups are read-only.
104 */
105 public static synchronized void initialize() {
106 iso3166Cache = new HashMap<>();
107 taginfoCache = new TreeMap<>();
108 try (CachedFile cf = new CachedFile("resource://data/" + FILENAME);
109 InputStream is = cf.getInputStream()) {
110 dataSet = OsmReader.parseDataSet(is, null);
111 Collection<OsmPrimitive> candidates = new ArrayList<>(dataSet.getWays());
112 candidates.addAll(dataSet.getRelations());
113 for (OsmPrimitive osm : candidates) {
114 String iso1 = osm.get(ISO3166_1);
115 String iso2 = osm.get(ISO3166_2);
116 if (iso1 != null || iso2 != null) {
117 GeoProperty<Boolean> gp;
118 if (osm instanceof Way) {
119 gp = new DefaultGeoProperty(Collections.singleton((Way) osm));
120 } else {
121 gp = new DefaultGeoProperty((Relation) osm);
122 }
123 GeoPropertyIndex<Boolean> gpi = new GeoPropertyIndex<>(gp, 24);
124 if (iso1 != null) {
125 iso3166Cache.put(iso1, gpi);
126 String taginfo = osm.get(TAGINFO);
127 if (taginfo != null) {
128 taginfoCache.put(iso1, taginfo);
129 }
130 }
131 if (iso2 != null) {
132 iso3166Cache.put(iso2, gpi);
133 }
134 }
135 }
136 } catch (IOException | IllegalDataException ex) {
137 throw new JosmRuntimeException(ex);
138 }
139 }
140
141 /**
142 * Returns a map of national taginfo instances for the given location.
143 * @param ll lat/lon where to look.
144 * @return a map of national taginfo instances for the given location (code / url)
145 * @since 15565
146 */
147 public static Map<String, String> getNationalTaginfoUrls(LatLon ll) {
148 Map<String, String> result = new TreeMap<>();
149 for (String code : iso3166Cache.entrySet().parallelStream().distinct()
150 .filter(e -> Boolean.TRUE.equals(e.getValue().get(ll)))
151 .map(Entry<String, GeoPropertyIndex<Boolean>>::getKey)
152 .collect(Collectors.toSet())) {
153 String taginfo = taginfoCache.get(code);
154 if (taginfo != null) {
155 result.put(code, taginfo);
156 }
157 }
158 return result;
159 }
160}
Note: See TracBrowser for help on using the repository browser.