- Timestamp:
- 2017-09-03T21:14:05+02:00 (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/io/OverpassDownloadReader.java
r12620 r12714 7 7 import java.io.InputStream; 8 8 import java.nio.charset.StandardCharsets; 9 import java.time.Duration; 10 import java.time.LocalDateTime; 11 import java.time.Period; 12 import java.time.ZoneOffset; 9 13 import java.util.EnumMap; 14 import java.util.Locale; 10 15 import java.util.Map; 11 16 import java.util.NoSuchElementException; … … 21 26 import org.openstreetmap.josm.data.Bounds; 22 27 import org.openstreetmap.josm.data.DataSource; 28 import org.openstreetmap.josm.data.coor.LatLon; 29 import org.openstreetmap.josm.data.osm.BBox; 23 30 import org.openstreetmap.josm.data.osm.DataSet; 24 31 import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 25 32 import org.openstreetmap.josm.data.osm.PrimitiveId; 26 33 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 34 import org.openstreetmap.josm.io.NameFinder.SearchResult; 27 35 import org.openstreetmap.josm.tools.HttpClient; 28 36 import org.openstreetmap.josm.tools.Logging; … … 146 154 return super.getRequestForBbox(lon1, lat1, lon2, lat2); 147 155 else { 148 final String query = this.overpassQuery.replace("{{bbox}}", lat1 + "," + lon1 + "," + lat2 + "," + lon2); 156 final String query = this.overpassQuery 157 .replace("{{bbox}}", bbox(lon1, lat1, lon2, lat2)) 158 .replace("{{center}}", center(lon1, lat1, lon2, lat2)); 149 159 final String expandedOverpassQuery = expandExtendedQueries(query); 150 160 return "interpreter" + DATA_PREFIX + Utils.encodeUrl(expandedOverpassQuery); … … 160 170 static String expandExtendedQueries(String query) { 161 171 final StringBuffer sb = new StringBuffer(); 162 final Matcher matcher = Pattern.compile("\\{\\{( geocodeArea):([^}]+)\\}\\}").matcher(query);172 final Matcher matcher = Pattern.compile("\\{\\{(date|geocodeArea|geocodeBbox|geocodeCoords|geocodeId):([^}]+)\\}\\}").matcher(query); 163 173 while (matcher.find()) { 164 174 try { 165 175 switch (matcher.group(1)) { 176 case "date": 177 matcher.appendReplacement(sb, date(matcher.group(2), LocalDateTime.now())); 178 break; 166 179 case "geocodeArea": 167 180 matcher.appendReplacement(sb, geocodeArea(matcher.group(2))); 168 181 break; 182 case "geocodeBbox": 183 matcher.appendReplacement(sb, geocodeBbox(matcher.group(2))); 184 break; 185 case "geocodeCoords": 186 matcher.appendReplacement(sb, geocodeCoords(matcher.group(2))); 187 break; 188 case "geocodeId": 189 matcher.appendReplacement(sb, geocodeId(matcher.group(2))); 190 break; 169 191 default: 170 192 Logging.warn("Unsupported syntax: " + matcher.group(1)); 171 193 } 172 } catch (UncheckedParseException ex) {194 } catch (UncheckedParseException | IOException | NoSuchElementException | IndexOutOfBoundsException ex) { 173 195 final String msg = tr("Failed to evaluate {0}", matcher.group()); 174 196 Logging.log(Logging.LEVEL_WARN, msg, ex); … … 180 202 } 181 203 182 private static String geocodeArea(String area) { 204 static String bbox(double lon1, double lat1, double lon2, double lat2) { 205 return lat1 + "," + lon1 + "," + lat2 + "," + lon2; 206 } 207 208 static String center(double lon1, double lat1, double lon2, double lat2) { 209 LatLon c = new BBox(lon1, lat1, lon2, lat2).getCenter(); 210 return c.lat()+ "," + c.lon(); 211 } 212 213 static String date(String humanDuration, LocalDateTime from) { 214 // Convert to ISO 8601. Replace months by X temporarily to avoid conflict with minutes 215 String duration = humanDuration.toLowerCase(Locale.ENGLISH).replace(" ", "") 216 .replaceAll("years?", "Y").replaceAll("months?", "X").replaceAll("weeks?", "W") 217 .replaceAll("days?", "D").replaceAll("hours?", "H").replaceAll("minutes?", "M").replaceAll("seconds?", "S"); 218 Matcher matcher = Pattern.compile( 219 "((?:[0-9]+Y)?(?:[0-9]+X)?(?:[0-9]+W)?)"+ 220 "((?:[0-9]+D)?)" + 221 "((?:[0-9]+H)?(?:[0-9]+M)?(?:[0-9]+(?:[.,][0-9]{0,9})?S)?)?").matcher(duration); 222 boolean javaPer = false; 223 boolean javaDur = false; 224 if (matcher.matches()) { 225 javaPer = matcher.group(1) != null && !matcher.group(1).isEmpty(); 226 javaDur = matcher.group(3) != null && !matcher.group(3).isEmpty(); 227 duration = 'P' + matcher.group(1).replace('X', 'M') + matcher.group(2); 228 if (javaDur) { 229 duration += 'T' + matcher.group(3); 230 } 231 } 232 233 // Duration is now a full ISO 8601 duration string. Unfortunately Java does not allow to parse it entirely. 234 // We must split the "period" (years, months, weeks, days) from the "duration" (days, hours, minutes, seconds). 235 Period p = null; 236 Duration d = null; 237 int idx = duration.indexOf('T'); 238 if (javaPer) { 239 p = Period.parse(javaDur ? duration.substring(0, idx) : duration); 240 } 241 if (javaDur) { 242 d = Duration.parse(javaPer ? 'P' + duration.substring(idx, duration.length()) : duration); 243 } else if (!javaPer) { 244 d = Duration.parse(duration); 245 } 246 247 // Now that period and duration are known, compute the correct date/time 248 LocalDateTime dt = from; 249 if (p != null) { 250 dt = dt.minus(p); 251 } 252 if (d != null) { 253 dt = dt.minus(d); 254 } 255 256 // Returns the date/time formatted in ISO 8601 257 return dt.toInstant(ZoneOffset.UTC).toString(); 258 } 259 260 private static SearchResult searchName(String area) throws IOException { 261 return NameFinder.queryNominatim(area).stream().filter( 262 x -> !OsmPrimitiveType.NODE.equals(x.getOsmId().getType())).iterator().next(); 263 } 264 265 static String geocodeArea(String area) throws IOException { 183 266 // Offsets defined in https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL#By_element_id 184 267 final EnumMap<OsmPrimitiveType, Long> idOffset = new EnumMap<>(OsmPrimitiveType.class); … … 186 269 idOffset.put(OsmPrimitiveType.WAY, 2_400_000_000L); 187 270 idOffset.put(OsmPrimitiveType.RELATION, 3_600_000_000L); 188 try { 189 final PrimitiveId osmId = NameFinder.queryNominatim(area).stream().filter( 190 x -> !OsmPrimitiveType.NODE.equals(x.getOsmId().getType())).iterator().next().getOsmId(); 191 return String.format("area(%d)", osmId.getUniqueId() + idOffset.get(osmId.getType())); 192 } catch (IOException | NoSuchElementException | IndexOutOfBoundsException ex) { 193 throw new UncheckedParseException(ex); 194 } 271 final PrimitiveId osmId = searchName(area).getOsmId(); 272 return String.format("area(%d)", osmId.getUniqueId() + idOffset.get(osmId.getType())); 273 } 274 275 static String geocodeBbox(String area) throws IOException { 276 Bounds bounds = searchName(area).getBounds(); 277 return bounds.getMinLat() + "," + bounds.getMinLon() + "," + bounds.getMaxLat() + "," + bounds.getMaxLon(); 278 } 279 280 static String geocodeCoords(String area) throws IOException { 281 SearchResult result = searchName(area); 282 return result.getLat() + "," + result.getLon(); 283 } 284 285 static String geocodeId(String area) throws IOException { 286 PrimitiveId osmId = searchName(area).getOsmId(); 287 return String.format("%s(%d)", osmId.getType().getAPIName(), osmId.getUniqueId()); 195 288 } 196 289
Note:
See TracChangeset
for help on using the changeset viewer.