kopia lustrzana https://github.com/onthegomap/planetiler
notes
rodzic
b31fa90b75
commit
6cc291b917
|
@ -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<Integer, String> 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())) + "%");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
Ładowanie…
Reference in New Issue