From 6cc291b9175bc9949114724e745daaf845a5a8f6 Mon Sep 17 00:00:00 2001 From: Mike Barry Date: Mon, 27 Mar 2023 06:44:07 -0400 Subject: [PATCH] notes --- .../planetiler/contour/EsaWorldcover.java | 56 +++++++++++++++++-- .../onthegomap/planetiler/contour/README.md | 47 ++++++++++++++++ 2 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 planetiler-core/src/main/java/com/onthegomap/planetiler/contour/README.md diff --git a/planetiler-core/src/main/java/com/onthegomap/planetiler/contour/EsaWorldcover.java b/planetiler-core/src/main/java/com/onthegomap/planetiler/contour/EsaWorldcover.java index 4f6d6854..1dc59a55 100644 --- a/planetiler-core/src/main/java/com/onthegomap/planetiler/contour/EsaWorldcover.java +++ b/planetiler-core/src/main/java/com/onthegomap/planetiler/contour/EsaWorldcover.java @@ -1,10 +1,41 @@ package com.onthegomap.planetiler.contour; +import static java.util.Map.entry; + +import com.carrotsearch.hppc.IntIntHashMap; +import com.carrotsearch.hppc.IntIntMap; import com.onthegomap.planetiler.config.PlanetilerConfig; -import com.onthegomap.planetiler.util.Downloader; +import java.awt.Color; +import java.awt.image.BufferedImage; import java.io.IOException; +import java.net.URL; +import java.util.Map; +import javax.imageio.ImageIO; public class EsaWorldcover { + // stack: + // nothing / built-up / moss / water + + // 1: shrub / grass / herbacious wetland + // 2: crop + // 3: tree / mangrove + // 4: very tree / mangrove + + // ice ? + private static final Map colors = Map.ofEntries( + entry(new Color(0, 100, 0, 255).getRGB(), "treecover"), + entry(new Color(255, 187, 34, 255).getRGB(), "shrubland"), + entry(new Color(255, 255, 76, 255).getRGB(), "grassland"), + entry(new Color(240, 150, 255, 255).getRGB(), "cropland"), + entry(new Color(250, 0, 0, 255).getRGB(), "builtup"), + entry(new Color(180, 180, 180, 255).getRGB(), "bare"), + entry(new Color(240, 240, 240, 255).getRGB(), "snow"), + entry(new Color(0, 100, 200, 255).getRGB(), "water"), + entry(new Color(0, 150, 160, 255).getRGB(), "wetland"), + entry(new Color(0, 207, 117, 255).getRGB(), "mangrove"), + entry(new Color(250, 230, 160, 255).getRGB(), "moss") + ); + static String getCoord(double ilon, double ilat) { int lon = (int) (Math.floor(ilon / 3) * 3); int lat = (int) (Math.floor(ilat / 3) * 3); @@ -16,12 +47,29 @@ public class EsaWorldcover { public static void main(String[] args) throws IOException { var config = PlanetilerConfig.defaults(); - String entry = "ESA_WorldCover_10m_2021_v200_" + getCoord(-71.5, 42.2) + "_Map.tif"; + String entry = "ESA_WorldCover_10m_2021_v200_" + getCoord(-72, 42) + "_Map.tif"; String url = "https://esa-worldcover.s3.amazonaws.com/v200/2021/map/" + entry; // ESA_WorldCover_10m_2021_v200_N42W072_Map.tif System.err.println("Getting " + url); - try (var is = Downloader.openStream(url, config)) { - System.err.println(is.readAllBytes().length); + BufferedImage image = ImageIO.read(new URL(url)); + System.err.println("width=" + image.getWidth()); + System.err.println("height=" + image.getHeight()); + IntIntMap counts = new IntIntHashMap(); + int idx = 0; + + int[] arr = new int[image.getWidth() * image.getHeight()]; + image.getRGB(0, 0, image.getWidth(), image.getHeight(), arr, 0, image.getWidth()); + System.err.println("got pixels"); + for (int y = 0; y < image.getHeight(); y++) { + for (int x = 0; x < image.getWidth(); x++) { + int color = arr[idx]; + counts.put(color, counts.getOrDefault(color, 0) + 1); + idx++; + } + } + for (var e : counts.keys()) { + System.err.println(e.value + " " + colors.get(e.value) + " " + + ((counts.get(e.value) * 100L) / ((long) image.getWidth() * image.getHeight())) + "%"); } } } diff --git a/planetiler-core/src/main/java/com/onthegomap/planetiler/contour/README.md b/planetiler-core/src/main/java/com/onthegomap/planetiler/contour/README.md new file mode 100644 index 00000000..b4536599 --- /dev/null +++ b/planetiler-core/src/main/java/com/onthegomap/planetiler/contour/README.md @@ -0,0 +1,47 @@ +# Raster DEM status + +## Contour Lines + +This appears to work fine with the following caveat: + +- AsterV3.java generates one contour shape from hi-res DEM then scales it down to lower zoom levels, this can result in + bad looking contour lines at low zooms. A better approach would be to downsample the DEM data to something appropriate + for each zoom level, then generate contour lines for that zoom. + +## Vector Hillshade + +Sort of works, caveats: + +- The polygons don't look right where the 1 degree tiles meet. +- It would probably be better to adopt maplibre GL JS's hillshading algorithm which adds shadows based on the slope more + so than the aspect so you can see details better on south and southwest sides when the illumination is from + northwest: https://github.com/maplibre/maplibre-gl-js/blob/main/src/shaders/hillshade.fragment.glsl +- It's _very_ slow + +## Landcover + +`EsaWorldcover.java` Doesn't do anything, but I did find out: + +- ESA worldcover dataset is hosted in a public S3 dataset so it's easy to download the 3 degree x 3 degree tiff + files https://registry.opendata.aws/esa-worldcover-vito/index.html +- The values are encoded by unique colors - see `EsaWorldcover.java` for an example parsing them +- We probably want to create "stacked" output polygons to create a greening effect when going from desert to grass to + forest, something like: + - omit built-up, moss, and water + - emit "ice" polygons + - emit a "greening stack" with: + - level 1 includes shrub/grass/herbacious wetland + - level 2 include all of level 1 plus also crop + - level 3 includes level 1 and 2 plus also tree and mangrove +- Most vector landcover datasets I see in the wild don't include features <300m wide, so we can downsample this 10m + dataset at least 30x to get started with. +- When downsampling, we probably want a bitmap for each output polygon, then consider a downsampled pixel a 1 if % of + matching raw input pixels within that output pixel is > 50% or so. + +The rough approach would look like: + +- generate bitmaps corresponding to each output polygon from raw input +- downsample initial bitmaps 30x +- vectorize, smooth, emit polygons +- repeat until you get down to z0: + - downsample another 2x, then vectorize, smooth, and emit polygons at the lower zoom level