kopia lustrzana https://github.com/onthegomap/planetiler
Handle elevations in units besides meters (#226)
rodzic
6b4eca3a78
commit
dab37f572e
|
@ -113,14 +113,14 @@ public class MountainPeak implements
|
|||
|
||||
@Override
|
||||
public void process(Tables.OsmPeakPoint element, FeatureCollector features) {
|
||||
Integer meters = Parse.parseIntSubstring(element.ele());
|
||||
Double meters = Parse.meters(element.ele());
|
||||
if (meters != null && Math.abs(meters) < 10_000) {
|
||||
var feature = features.point(LAYER_NAME)
|
||||
.setAttr(Fields.CLASS, element.source().getTag("natural"))
|
||||
.putAttrs(LanguageUtils.getNames(element.source().tags(), translations))
|
||||
.putAttrs(elevationTags(meters))
|
||||
.setSortKeyDescending(
|
||||
meters +
|
||||
meters.intValue() +
|
||||
(nullIfEmpty(element.wikipedia()) != null ? 10_000 : 0) +
|
||||
(nullIfEmpty(element.name()) != null ? 10_000 : 0)
|
||||
)
|
||||
|
|
|
@ -49,9 +49,9 @@ public class Utils {
|
|||
}
|
||||
|
||||
/** Returns a map with {@code ele} (meters) and {ele_ft} attributes from an elevation in meters. */
|
||||
public static Map<String, Object> elevationTags(int meters) {
|
||||
public static Map<String, Object> elevationTags(double meters) {
|
||||
return Map.of(
|
||||
"ele", meters,
|
||||
"ele", (int) Math.round(meters),
|
||||
"ele_ft", (int) Math.round(meters * 3.2808399)
|
||||
);
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ public class Utils {
|
|||
* meters} can be parsed as a valid number.
|
||||
*/
|
||||
public static Map<String, Object> elevationTags(String meters) {
|
||||
Integer ele = Parse.parseIntSubstring(meters);
|
||||
Double ele = Parse.meters(meters);
|
||||
return ele == null ? Map.of() : elevationTags(ele);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,36 @@ class AerodromeLabelTest extends AbstractLayerTest {
|
|||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testElevationFeet() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"ele", 100,
|
||||
"ele_ft", 328
|
||||
)), process(pointFeature(Map.of(
|
||||
"aeroway", "aerodrome",
|
||||
"name", "osm name",
|
||||
"ele", "328'",
|
||||
"aerodrome", "international",
|
||||
"iata", "123",
|
||||
"icao", "1234"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testElevationFeetInches() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"ele", 100,
|
||||
"ele_ft", 328
|
||||
)), process(pointFeature(Map.of(
|
||||
"aeroway", "aerodrome",
|
||||
"name", "osm name",
|
||||
"ele", "328' 1\"",
|
||||
"aerodrome", "international",
|
||||
"iata", "123",
|
||||
"icao", "1234"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInternational() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
|
|
|
@ -75,6 +75,30 @@ class MountainPeakTest extends AbstractLayerTest {
|
|||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testElevationFeet() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "volcano",
|
||||
"ele", 30,
|
||||
"ele_ft", 100
|
||||
)), process(pointFeature(Map.of(
|
||||
"natural", "volcano",
|
||||
"ele", "100'"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testElevationFeetInches() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "volcano",
|
||||
"ele", 31,
|
||||
"ele_ft", 101
|
||||
)), process(pointFeature(Map.of(
|
||||
"natural", "volcano",
|
||||
"ele", "100' 11\""
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSaddle() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
|
|
|
@ -12,6 +12,11 @@ public class Parse {
|
|||
|
||||
private static final Pattern INT_SUBSTRING_PATTERN = Pattern.compile("^(-?\\d+)(\\D|$)");
|
||||
private static final Pattern TO_ROUND_INT_SUBSTRING_PATTERN = Pattern.compile("^(-?[\\d.]+)(\\D|$)");
|
||||
// See https://wiki.openstreetmap.org/wiki/Map_features/Units
|
||||
private static final Pattern DISTANCE =
|
||||
Pattern.compile(
|
||||
"(?<value>-?[\\d.]+)\\s*((?<mi>mi)|(?<m>m|$)|(?<km>km|kilom)|(?<ft>ft|')|(?<in>in|\")|(?<nmi>nmi|international nautical mile|nautical))",
|
||||
Pattern.CASE_INSENSITIVE);
|
||||
|
||||
/** Returns {@code tag} as a long or null if invalid. */
|
||||
public static Long parseLongOrNull(Object tag) {
|
||||
|
@ -131,4 +136,49 @@ public class Parse {
|
|||
throw new IllegalArgumentException("Unable to parse size: " + value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses {@code tag} as a measure of distance with unit, converted to a round number of meters or {@code null} if
|
||||
* invalid.
|
||||
*
|
||||
* See <a href="https://wiki.openstreetmap.org/wiki/Map_features/Units">Map features/Units</a> for the list of
|
||||
* supported units.
|
||||
*/
|
||||
public static Double meters(Object tag) {
|
||||
if (tag != null) {
|
||||
if (tag instanceof Number num) {
|
||||
return num.doubleValue();
|
||||
}
|
||||
var str = tag.toString();
|
||||
var matcher = DISTANCE.matcher(str);
|
||||
if (matcher.find()) {
|
||||
try {
|
||||
double value = Double.parseDouble(matcher.group("value"));
|
||||
if (matcher.group("m") != null) {
|
||||
// value *= 1;
|
||||
} else if (matcher.group("km") != null) {
|
||||
value *= 1000d;
|
||||
} else if (matcher.group("mi") != null) {
|
||||
value *= 1609.344;
|
||||
} else if (matcher.group("nmi") != null) {
|
||||
value *= 1852d;
|
||||
} else if (matcher.group("ft") != null) {
|
||||
value *= 12 * 0.0254;
|
||||
// handle 15'3"
|
||||
if (matcher.find() && matcher.group("in") != null) {
|
||||
value += Double.parseDouble(matcher.group("value")) * 0.0254;
|
||||
}
|
||||
} else if (matcher.group("in") != null) {
|
||||
value *= 0.0254;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return value;
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.onthegomap.planetiler.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
|
||||
|
||||
|
@ -52,6 +53,45 @@ class ParseTest {
|
|||
assertEquals(out, Parse.direction(in));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource(value = {
|
||||
"1, 1",
|
||||
"100, 100",
|
||||
"-1.23 m, -1.23",
|
||||
"100.2, 100.2",
|
||||
"1m, 1",
|
||||
"1meter, 1",
|
||||
"100 meters, 100",
|
||||
"1.5m, 1.5",
|
||||
"1km, 1000",
|
||||
"0.2km, 200",
|
||||
"0.2 km, 200",
|
||||
"1mi, 1609.344",
|
||||
"1 mi, 1609.344",
|
||||
"328', 99.974",
|
||||
"328ft, 99.974",
|
||||
"328'11\", 100.254",
|
||||
"328ft 11in, 100.254",
|
||||
"garbage, null",
|
||||
"1nmi, 1852",
|
||||
"1.5 nmi, 2778",
|
||||
"1..5 nmi, null",
|
||||
"36\", 0.9144",
|
||||
"1'11\", 0.584",
|
||||
"132.74', 40.4592",
|
||||
"132'8.88\", 40.4592",
|
||||
"1'11m, 0.305",
|
||||
"1.5 smoots, null",
|
||||
}, nullValues = "null")
|
||||
void testLength(String in, Double out) {
|
||||
Double result = Parse.meters(in);
|
||||
if (out == null) {
|
||||
assertNull(result);
|
||||
} else {
|
||||
assertEquals(result, out, 1e-3);
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource(value = {
|
||||
"1, 1",
|
||||
|
|
Ładowanie…
Reference in New Issue