diff --git a/src/main/java/org/openmaptiles/layers/Housenumber.java b/src/main/java/org/openmaptiles/layers/Housenumber.java index 66338597..cebfb8a3 100644 --- a/src/main/java/org/openmaptiles/layers/Housenumber.java +++ b/src/main/java/org/openmaptiles/layers/Housenumber.java @@ -43,9 +43,15 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE import com.onthegomap.planetiler.geo.GeometryException; import com.onthegomap.planetiler.stats.Stats; import com.onthegomap.planetiler.util.Translations; +import java.util.Arrays; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import org.openmaptiles.generated.OpenMapTilesSchema; import org.openmaptiles.generated.Tables; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Defines the logic for generating map elements in the {@code housenumber} layer from source features. @@ -59,13 +65,63 @@ public class Housenumber implements Tables.OsmHousenumberPoint.Handler, ForwardingProfile.FeaturePostProcessor { - public Housenumber(Translations translations, PlanetilerConfig config, Stats stats) {} + private static final Logger LOGGER = LoggerFactory.getLogger(Housenumber.class); + private static final Character OSM_SEPARATOR = ';'; + private static final String DISPLAY_SEPARATOR = "–"; + private static final Pattern NO_CONVERSION_PATTERN = Pattern.compile("[^0-9;]"); + private final Stats stats; + + public Housenumber(Translations translations, PlanetilerConfig config, Stats stats) { + this.stats = stats; + } + + private static String displayHousenumberNonumeric(String[] numbers) { + return numbers[0] + .concat(DISPLAY_SEPARATOR) + .concat(numbers[numbers.length - 1]); + } + + protected static String displayHousenumber(String housenumber) { + if (housenumber.indexOf(OSM_SEPARATOR) < 0) { + return housenumber; + } + + String[] numbers = Arrays.stream(housenumber.split(OSM_SEPARATOR.toString())) + .filter(n -> !n.trim().isEmpty()) + .toArray(String[]::new); + if (numbers.length <= 0) { + // not much to do with strange/invalid entries like "3;" or ";" etc. + return housenumber; + } + + Matcher matcher = NO_CONVERSION_PATTERN.matcher(housenumber); + if (matcher.find()) { + return displayHousenumberNonumeric(numbers); + } + + // numeric display house number + var statistics = Arrays.stream(numbers) + .collect(Collectors.summarizingInt(Integer::parseUnsignedInt)); + return String.valueOf(statistics.getMin()) + .concat(DISPLAY_SEPARATOR) + .concat(String.valueOf(statistics.getMax())); + } @Override public void process(Tables.OsmHousenumberPoint element, FeatureCollector features) { + String housenumber; + try { + housenumber = displayHousenumber(element.housenumber()); + } catch (NumberFormatException e) { + // should not be happening (thanks to NO_CONVERSION_PATTERN) but ... + stats.dataError("housenumber_range"); + LOGGER.warn("Failed to convert housenumber range: {}", element.housenumber()); + housenumber = element.housenumber(); + } + features.centroidIfConvex(LAYER_NAME) .setBufferPixels(BUFFER_SIZE) - .setAttr(Fields.HOUSENUMBER, element.housenumber()) + .setAttr(Fields.HOUSENUMBER, housenumber) .setMinZoom(14); } diff --git a/src/test/java/org/openmaptiles/layers/HousenumberTest.java b/src/test/java/org/openmaptiles/layers/HousenumberTest.java index 6ead5e96..e4083203 100644 --- a/src/test/java/org/openmaptiles/layers/HousenumberTest.java +++ b/src/test/java/org/openmaptiles/layers/HousenumberTest.java @@ -1,5 +1,7 @@ package org.openmaptiles.layers; +import static org.junit.jupiter.api.Assertions.assertEquals; + import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; @@ -27,4 +29,43 @@ void testHousenumber() { "addr:housenumber", "10" )))); } + + @Test + void testDisplayHousenumberNonRange() { + final String HOUSENUMBER = "1"; + assertEquals(HOUSENUMBER, Housenumber.displayHousenumber(HOUSENUMBER)); + } + + @Test + void testDisplayHousenumberNonnumericRange() { + final String HOUSENUMBER = "1;1a;2;2/b;20;3"; + assertEquals("1–3", Housenumber.displayHousenumber(HOUSENUMBER)); + } + + @Test + void testDisplayHousenumberNonnumericRangeBroken() { + final String HOUSENUMBER = "1;1a;2;2/b;20;3;"; + assertEquals("1–3", Housenumber.displayHousenumber(HOUSENUMBER)); + } + + @Test + void testDisplayHousenumberNumericRange() { + final String HOUSENUMBER = "1;2;20;3"; + assertEquals("1–20", Housenumber.displayHousenumber(HOUSENUMBER)); + } + + @Test + void testDisplayHousenumberNumericRangeBroken() { + final String HOUSENUMBER = "1;2;20;3;"; + assertEquals("1–20", Housenumber.displayHousenumber(HOUSENUMBER)); + } + + @Test + void testDisplayHousenumberExtraBroken() { + final String HOUSENUMBER_1 = ";"; + assertEquals(HOUSENUMBER_1, Housenumber.displayHousenumber(HOUSENUMBER_1)); + + final String HOUSENUMBER_2 = ";;"; + assertEquals(HOUSENUMBER_2, Housenumber.displayHousenumber(HOUSENUMBER_2)); + } }