From d36af297082d1c0cc8e17b1e367cf19797968c41 Mon Sep 17 00:00:00 2001 From: Mike Barry Date: Tue, 6 Apr 2021 20:33:35 -0400 Subject: [PATCH] argument parsing --- pom.xml | 15 ++++ src/main/java/com/onthegomap/flatmap/App.java | 16 ---- .../java/com/onthegomap/flatmap/GeoUtils.java | 53 +++++++++++++ .../com/onthegomap/flatmap/OsmInputFile.java | 62 +++++++++++++++ .../flatmap/profiles/Arguments.java | 78 +++++++++++++++++++ .../flatmap/profiles/OpenMapTilesProfile.java | 41 ++++++++++ .../onthegomap/flatmap/profiles/Profile.java | 5 ++ .../com/onthegomap/flatmap/stats/Stats.java | 5 ++ src/main/resources/log4j.properties | 7 ++ .../java/com/onthegomap/flatmap/AppTest.java | 13 ---- .../com/onthegomap/flatmap/GeoUtilsTest.java | 5 ++ 11 files changed, 271 insertions(+), 29 deletions(-) delete mode 100644 src/main/java/com/onthegomap/flatmap/App.java create mode 100644 src/main/java/com/onthegomap/flatmap/GeoUtils.java create mode 100644 src/main/java/com/onthegomap/flatmap/OsmInputFile.java create mode 100644 src/main/java/com/onthegomap/flatmap/profiles/Arguments.java create mode 100644 src/main/java/com/onthegomap/flatmap/profiles/OpenMapTilesProfile.java create mode 100644 src/main/java/com/onthegomap/flatmap/profiles/Profile.java create mode 100644 src/main/java/com/onthegomap/flatmap/stats/Stats.java create mode 100644 src/main/resources/log4j.properties delete mode 100644 src/test/java/com/onthegomap/flatmap/AppTest.java create mode 100644 src/test/java/com/onthegomap/flatmap/GeoUtilsTest.java diff --git a/pom.xml b/pom.xml index 7782f15d..14c006bd 100644 --- a/pom.xml +++ b/pom.xml @@ -80,6 +80,21 @@ msgpack-core 0.8.22 + + org.slf4j + slf4j-api + 1.7.30 + + + org.slf4j + slf4j-log4j12 + 1.7.30 + + + log4j + log4j + 1.2.17 + org.junit.jupiter diff --git a/src/main/java/com/onthegomap/flatmap/App.java b/src/main/java/com/onthegomap/flatmap/App.java deleted file mode 100644 index a50ff83c..00000000 --- a/src/main/java/com/onthegomap/flatmap/App.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.onthegomap.flatmap; - -public record App() { - - record Greeting(int x) { - - } - - public static void main(String[] args) { - System.out.println(new App().getGreeting()); - } - - public String getGreeting() { - return "hello world " + new Greeting(1); - } -} diff --git a/src/main/java/com/onthegomap/flatmap/GeoUtils.java b/src/main/java/com/onthegomap/flatmap/GeoUtils.java new file mode 100644 index 00000000..034b3ce2 --- /dev/null +++ b/src/main/java/com/onthegomap/flatmap/GeoUtils.java @@ -0,0 +1,53 @@ +package com.onthegomap.flatmap; + +public class GeoUtils { + + private static final double DEGREES_TO_RADIANS = Math.PI / 180; + private static final double RADIANS_TO_DEGREES = 180 / Math.PI; + private static final double MAX_LAT = getWorldLat(-0.1); + private static final double MIN_LAT = getWorldLat(1.1); + public static double[] WORLD_BOUNDS = new double[]{0, 0, 1, 1}; + public static double[] WORLD_LAT_LON_BOUNDS = toLatLonBoundsBounds(WORLD_BOUNDS); + + public static double[] toLatLonBoundsBounds(double[] worldBounds) { + return new double[]{ + getWorldLon(worldBounds[0]), + getWorldLat(worldBounds[1]), + getWorldLon(worldBounds[2]), + getWorldLat(worldBounds[3]) + }; + } + + public static double[] toWorldBounds(double[] lonLatBounds) { + return new double[]{ + getWorldX(lonLatBounds[0]), + getWorldY(lonLatBounds[1]), + getWorldX(lonLatBounds[2]), + getWorldY(lonLatBounds[3]) + }; + } + + public static double getWorldLon(double x) { + return x * 360 - 180; + } + + public static double getWorldLat(double y) { + double n = Math.PI - 2 * Math.PI * y; + return RADIANS_TO_DEGREES * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))); + } + + public static double getWorldX(double lon) { + return (lon + 180) / 360; + } + + public static double getWorldY(double lat) { + if (lat <= MIN_LAT) { + return 1.1; + } + if (lat >= MAX_LAT) { + return -0.1; + } + double sin = Math.sin(lat * DEGREES_TO_RADIANS); + return 0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI; + } +} diff --git a/src/main/java/com/onthegomap/flatmap/OsmInputFile.java b/src/main/java/com/onthegomap/flatmap/OsmInputFile.java new file mode 100644 index 00000000..e5b93fb3 --- /dev/null +++ b/src/main/java/com/onthegomap/flatmap/OsmInputFile.java @@ -0,0 +1,62 @@ +package com.onthegomap.flatmap; + +import com.google.protobuf.ByteString; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.zip.DataFormatException; +import java.util.zip.Inflater; +import org.openstreetmap.osmosis.osmbinary.Fileformat.Blob; +import org.openstreetmap.osmosis.osmbinary.Fileformat.BlobHeader; +import org.openstreetmap.osmosis.osmbinary.Osmformat.HeaderBBox; +import org.openstreetmap.osmosis.osmbinary.Osmformat.HeaderBlock; +import org.openstreetmap.osmosis.osmbinary.file.FileFormatException; + +public class OsmInputFile { + + private final File file; + + public OsmInputFile(File file) { + this.file = file; + } + + public double[] getBounds() { + try (var input = new FileInputStream(file)) { + var datinput = new DataInputStream(input); + int headersize = datinput.readInt(); + if (headersize > 65536) { + throw new FileFormatException( + "Unexpectedly long header 65536 bytes. Possibly corrupt file " + file); + } + byte[] buf = datinput.readNBytes(headersize); + BlobHeader header = BlobHeader.parseFrom(buf); + if (!header.getType().equals("OSMHeader")) { + throw new IllegalArgumentException("Expecting OSMHeader got " + header.getType()); + } + buf = datinput.readNBytes(header.getDatasize()); + Blob blob = Blob.parseFrom(buf); + ByteString data = null; + if (blob.hasRaw()) { + data = blob.getRaw(); + } else if (blob.hasZlibData()) { + byte[] buf2 = new byte[blob.getRawSize()]; + Inflater decompresser = new Inflater(); + decompresser.setInput(blob.getZlibData().toByteArray()); + decompresser.inflate(buf2); + decompresser.end(); + data = ByteString.copyFrom(buf2); + } + HeaderBlock headerblock = HeaderBlock.parseFrom(data); + HeaderBBox bbox = headerblock.getBbox(); + return new double[]{ + bbox.getLeft() / 1e9, + bbox.getBottom() / 1e9, + bbox.getRight() / 1e9, + bbox.getTop() / 1e9 + }; + } catch (IOException | DataFormatException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/com/onthegomap/flatmap/profiles/Arguments.java b/src/main/java/com/onthegomap/flatmap/profiles/Arguments.java new file mode 100644 index 00000000..28e7718c --- /dev/null +++ b/src/main/java/com/onthegomap/flatmap/profiles/Arguments.java @@ -0,0 +1,78 @@ +package com.onthegomap.flatmap.profiles; + +import com.onthegomap.flatmap.GeoUtils; +import com.onthegomap.flatmap.OsmInputFile; +import java.io.File; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Arguments { + + private static final Logger LOGGER = LoggerFactory.getLogger(Arguments.class); + + public Arguments(String[] args) { + } + + private String getArg(String key, String defaultValue) { + return System.getProperty(key, defaultValue).trim(); + } + + public double[] bounds(String arg, String description, OsmInputFile osmInputFile) { + String input = System.getProperty(arg, null); + double[] result; + if (input == null) { + // get from osm.pbf + result = osmInputFile.getBounds(); + } else if ("world".equalsIgnoreCase(input)) { + result = GeoUtils.WORLD_LAT_LON_BOUNDS; + } else { + result = Stream.of(input.split("[\\s,]+")).mapToDouble(Double::parseDouble).toArray(); + } + LOGGER.info(description + ": " + Arrays.toString(result)); + return result; + } + + public String get(String arg, String description, String defaultValue) { + String value = getArg(arg, defaultValue); + LOGGER.info(description + ": " + value); + return value; + } + + public File file(String arg, String description, String defaultValue) { + String value = getArg(arg, defaultValue); + File file = new File(value); + LOGGER.info(description + ": " + value); + return file; + } + + public File inputFile(String arg, String description, String defaultValue) { + File file = file(arg, description, defaultValue); + if (!file.exists()) { + throw new IllegalArgumentException(file + " does not exist"); + } + return file; + } + + public boolean get(String arg, String description, boolean defaultValue) { + boolean value = "true".equalsIgnoreCase(getArg(arg, Boolean.toString(defaultValue))); + LOGGER.info(description + ": " + value); + return value; + } + + public List get(String arg, String description, String[] defaultValue) { + String value = getArg(arg, String.join(",", defaultValue)); + List results = List.of(value.split("[\\s,]+")); + LOGGER.info(description + ": " + value); + return results; + } + + public int threads() { + String value = getArg("threads", Integer.toString(Runtime.getRuntime().availableProcessors())); + int threads = Math.max(2, Integer.parseInt(value)); + LOGGER.info("num threads: " + threads); + return threads; + } +} diff --git a/src/main/java/com/onthegomap/flatmap/profiles/OpenMapTilesProfile.java b/src/main/java/com/onthegomap/flatmap/profiles/OpenMapTilesProfile.java new file mode 100644 index 00000000..7955904d --- /dev/null +++ b/src/main/java/com/onthegomap/flatmap/profiles/OpenMapTilesProfile.java @@ -0,0 +1,41 @@ +package com.onthegomap.flatmap.profiles; + + +import com.graphhopper.util.StopWatch; +import com.onthegomap.flatmap.OsmInputFile; +import java.io.File; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OpenMapTilesProfile implements Profile { + + private static final Logger LOGGER = LoggerFactory.getLogger(OpenMapTilesProfile.class); + + public static void main(String[] args) { + StopWatch watch = new StopWatch().start(); + Arguments arguments = new Arguments(args); + OsmInputFile osmInputFile = new OsmInputFile(arguments.inputFile("input", "OSM input file", + "./data/sources/massachusetts-latest.osm.pbf")); + File centerlines = arguments.inputFile("centerline", "lake centerlines input", + "./data/sources/lake_centerline.shp.zip"); + File naturalEarth = arguments.inputFile("natural_earth", "natural earth input", + "./data/sources/natural_earth_vector.sqlite.zip"); + File waterPolygons = arguments.inputFile("water_polygons", "water polygons input", + "./data/sources/water-polygons-split-3857.zip"); + double[] bounds = arguments.bounds("bounds", "bounds", osmInputFile); + int threads = arguments.threads(); + File tmpDir = arguments.file("tmpdir", "temp directory", "./data/tmp"); + boolean fetchWikidata = arguments.get("fetch_wikidata", "fetch wikidata translations", false); + boolean useWikidata = arguments.get("use_wikidata", "use wikidata translations", true); + File wikidataNamesFile = arguments.file("wikidata_cache", "wikidata cache file", + "./data/sources/wikidata_names.json"); + String output = arguments.get("output", "mbtiles output file", "./massachusetts.mbtiles"); + List languages = arguments.get("name_languages", "languages to use", + "en,ru,ar,zh,ja,ko,fr,de,fi,pl,es,be,br,he".split(",")); + + var profile = new OpenMapTilesProfile(); + + LOGGER.info("FINISHED! " + watch.stop()); + } +} diff --git a/src/main/java/com/onthegomap/flatmap/profiles/Profile.java b/src/main/java/com/onthegomap/flatmap/profiles/Profile.java new file mode 100644 index 00000000..a18cf663 --- /dev/null +++ b/src/main/java/com/onthegomap/flatmap/profiles/Profile.java @@ -0,0 +1,5 @@ +package com.onthegomap.flatmap.profiles; + +public interface Profile { + +} diff --git a/src/main/java/com/onthegomap/flatmap/stats/Stats.java b/src/main/java/com/onthegomap/flatmap/stats/Stats.java new file mode 100644 index 00000000..79321b74 --- /dev/null +++ b/src/main/java/com/onthegomap/flatmap/stats/Stats.java @@ -0,0 +1,5 @@ +package com.onthegomap.flatmap.stats; + +public interface Stats { + +} diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties new file mode 100644 index 00000000..52cbe313 --- /dev/null +++ b/src/main/resources/log4j.properties @@ -0,0 +1,7 @@ +# Root logger option +log4j.rootLogger=INFO, stdout +# Direct log messages to stdout +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss.SSS} [%t] %p - %m%n diff --git a/src/test/java/com/onthegomap/flatmap/AppTest.java b/src/test/java/com/onthegomap/flatmap/AppTest.java deleted file mode 100644 index ec83f5a0..00000000 --- a/src/test/java/com/onthegomap/flatmap/AppTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.onthegomap.flatmap; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.Test; - -public class AppTest { - - @Test - public void testFast() { - assertEquals("hello world", new App().getGreeting()); - } -} diff --git a/src/test/java/com/onthegomap/flatmap/GeoUtilsTest.java b/src/test/java/com/onthegomap/flatmap/GeoUtilsTest.java new file mode 100644 index 00000000..9a88a88c --- /dev/null +++ b/src/test/java/com/onthegomap/flatmap/GeoUtilsTest.java @@ -0,0 +1,5 @@ +package com.onthegomap.flatmap; + +public class GeoUtilsTest { + +}