From 159bc8ffae741e128e71387974e17b7084ea2cd8 Mon Sep 17 00:00:00 2001 From: Ryan Moore Date: Fri, 18 Aug 2023 15:33:35 +1200 Subject: [PATCH] added symbol: 418 Prominent bush or tree --- src/convert_world.py | 26 +++++++++++++------ src/create_map.r | 61 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 69 insertions(+), 18 deletions(-) diff --git a/src/convert_world.py b/src/convert_world.py index b1906ac..1101526 100644 --- a/src/convert_world.py +++ b/src/convert_world.py @@ -125,11 +125,6 @@ def chunk_at(region, cx, cz): bx2 += CROP_BUFFER + 1 bz2 += CROP_BUFFER + 1 -print( - ceil((bz2 - bz1) / args.downsample), - ceil((bx2 - bx1) / args.downsample) -) - create_mat = lambda dtype : np.mat(np.zeros(( ceil((bz2 - bz1) / args.downsample), ceil((bx2 - bx1) / args.downsample) @@ -138,7 +133,8 @@ def chunk_at(region, cx, cz): data = { "dem": create_mat(np.uint8) if args.compress_height_limit else create_mat(np.int16), "vegetation": create_mat(np.bool_), - "landcover": create_mat(np.uint8) + "landcover": create_mat(np.uint8), + "trees": create_mat(np.bool_) } for row, bz in enumerate(range(bz1, bz2, args.downsample)): @@ -166,14 +162,23 @@ def chunk_at(region, cx, cz): max_height = int(chunk.heightmap[bz_in_c, bx_in_c]) if chunk.heightmap.any() else 255 min_height = 0 + canopy = False + tree = False for by in range(max_height, min_height, -1): block = chunk.get_block(bx_in_c, by, bz_in_c) - + # -- surface processes: dem and landcover -- + if block.id == "air": + canopy = False + tree = False + continue if block.id in surface_blocks: data["dem"][entry] = by data["landcover"][entry] = surface_blocks.index(block.id) + if tree: + data["trees"][entry] = 1 break + elif "water" in surface_blocks: # inherently waterlogged blocks, see https://minecraft.fandom.com/wiki/Waterlogging if block.id in ["seagrass", "tall_seagrass", "kelp", "kelp_plant"]: @@ -190,6 +195,11 @@ def chunk_at(region, cx, cz): # -- other processes: vegetation -- if block.id.endswith("leaves"): data["vegetation"][entry] = 1 + canopy = True + + # -- other processes: trees -- + if block.id.endswith("log") and canopy: + tree = True logging.info("Writing data...") try: @@ -205,4 +215,4 @@ def chunk_at(region, cx, cz): dtype=data.dtype) )) # store downsampling amount as image resolution - image.save(filename, dpi=tuple(np.repeat(args.downsample * 300, 2))) \ No newline at end of file + image.save(filename, dpi=tuple(np.repeat(args.downsample * 300, 2))) diff --git a/src/create_map.r b/src/create_map.r index d9d84a8..1f50a43 100644 --- a/src/create_map.r +++ b/src/create_map.r @@ -35,20 +35,31 @@ exif <- tiff::readTIFF("data/dem.tif", payload=F) resolution <- exif$x.resolution / 300 dpi <- 300 in_per_block <- 39.3701 + canopy_buffer <- 2 crop_buffer <- 16 -dotwidth <- function (mmwidth) { +# helper functions to convert mm to tmap's internal sizing +lwd_from_mm <- function (mmwidth) { in_per_mm <- in_per_block / 1000 dots_per_mm <- in_per_mm * dpi - mmwidth * dots_per_mm + (lwd_from_mm <- mmwidth * dots_per_mm) +} +size_from_mm <- function (mmwidth) { + default_font_size <- 12 + font_to_point_margin <- 0.3 + + lwd_from_mm <- lwd_from_mm(mmwidth) + pointsize <- default_font_size - (2 * font_to_point_margin) + size_from_mm <- (lwd_from_mm / pointsize) ^ 2 } log_info("Reading data...") data <- lapply(list( dem=terra::rast("data/dem.tif"), vegetation=terra::rast("data/vegetation.tif"), - landcover=terra::rast("data/landcover.tif") + landcover=terra::rast("data/landcover.tif"), + trees=terra::rast("data/trees.tif") ), function(raster) {crs(raster) <- "ESRI:53032"; raster}) bounds <- st_as_sf(vect(ext( @@ -68,7 +79,7 @@ contours <- list( to = max(data$dem[]), by = settings$interval )), - render=list(tm_lines(lwd = dotwidth(0.14), col = "#D15C00")), + render=list(tm_lines(lwd = lwd_from_mm(0.14), col = "#D15C00")), smoothing=3 ) @@ -78,7 +89,10 @@ water[data$landcover != (match("water", surface_blocks) - 1)] <- NA water <- list( feature=water |> terra::as.polygons(), - render=list(tm_fill(col = "#00FFFF"), tm_borders(lwd = dotwidth(0.18), col = "black")), + render=list( + tm_fill(col = "#00FFFF"), + tm_borders(lwd = lwd_from_mm(0.18), col = "black") + ), smoothing=3 ) @@ -91,22 +105,49 @@ canopy <- list( smoothing=20 ) -symbols <- list( +# point symbols should only be created if resolution has block accuracy +if (resolution == 1) { + log_info("Creating trees...") + data$trees[data$trees == 0] <- NA + trees <- list( + feature=as.points(data$trees), + render=list( + tm_symbols( + size = size_from_mm(0.4), + alpha=0, + border.col = "#3DFF17", + border.lwd = lwd_from_mm(0.2)) + ) + ) +} + +if (resolution == 1) { # include point symbols + symbols <- list( + canopy=canopy, + contours=contours, + water=water, + trees=trees + ) +} else { # exclude point symbols + symbols <- list( canopy=canopy, contours=contours, water=water -) # symbols in overprinting order for rendering + ) +} log_info("Applying geometry operations to symbols...") symbols <- mapply(function(symbol, name) { log_info(sprintf("Applying geometry operations to %s...", name)) feature <- symbol$feature |> st_as_sf() smoothing <- symbol$smoothing * resolution * settings$smoothing - if (smoothing >= 0.1) { + if (!("POINT" %in% (feature |> st_geometry_type() |> as.character()))) { + if (smoothing >= 0.1) { feature <- feature |> smoothr::smooth(method="ksmooth", smoothness = smoothing) - } - if (!settings$`keep-crumbs`) { + } + if (!settings$`keep-crumbs`) { feature <- feature |> smoothr::drop_crumbs(12) + } } feature <- tryCatch({ feature |> st_crop(bounds)