#' Combined: Create master grid and split TIFFs into tiles #' ==================================================================== #' #' Purpose: #' 1. Check all daily TIFFs for matching extents #' 2. Create master 5×5 grid covering all TIFFs #' 3. Split each daily TIFF into 25 tiles using the master grid #' 4. Save tiles in date-specific folders: daily_tiles/[DATE]/[DATE]_[TILE_ID].tif library(terra) library(sf) # ============================================================================ # CONFIGURATION # ============================================================================ PROJECT <- "angata" TIFF_FOLDER <- file.path("laravel_app", "storage", "app", PROJECT, "merged_tif_8b") OUTPUT_FOLDER <- file.path("laravel_app", "storage", "app", PROJECT, "daily_tiles_split") # Grid dimensions will be auto-determined based on ROI size # Default: 5×5 = 25 tiles # If ROI < 10×10 km: 1×1 = 1 tile (no splitting needed) GRID_NROWS <- 5 GRID_NCOLS <- 5 cat("Combined: Create Master Grid (5x5) and Split TIFFs into Tiles\n") # ============================================================================ # PART 1: CHECK TIFF EXTENTS AND CREATE MASTER GRID # ============================================================================ cat("\n[PART 1] Creating Master Grid\n") cat("\n[1] Checking TIFF extents...\n") tiff_files <- list.files(TIFF_FOLDER, pattern = "\\.tif$", full.names = FALSE) tiff_files <- sort(tiff_files) if (length(tiff_files) == 0) { stop("No TIFF files found in ", TIFF_FOLDER) } cat(" Found", length(tiff_files), "TIFF file(s)\n") # Load all extents extents <- list() for (i in seq_along(tiff_files)) { tiff_path <- file.path(TIFF_FOLDER, tiff_files[i]) raster <- terra::rast(tiff_path) ext <- terra::ext(raster) extents[[i]] <- ext } # Check if all extents match cat("\n[2] Comparing extents...\n") tolerance <- 1e-8 all_match <- TRUE first_ext <- extents[[1]] for (i in 2:length(extents)) { curr_ext <- extents[[i]] match <- ( abs(curr_ext$xmin - first_ext$xmin) < tolerance && abs(curr_ext$xmax - first_ext$xmax) < tolerance && abs(curr_ext$ymin - first_ext$ymin) < tolerance && abs(curr_ext$ymax - first_ext$ymax) < tolerance ) if (!match) { all_match <- FALSE cat(" ✗ Extent mismatch: ", tiff_files[1], " vs ", tiff_files[i], "\n", sep = "") cat(" File 1: X [", round(first_ext$xmin, 6), ", ", round(first_ext$xmax, 6), "] ", "Y [", round(first_ext$ymin, 6), ", ", round(first_ext$ymax, 6), "]\n", sep = "") cat(" File ", i, ": X [", round(curr_ext$xmin, 6), ", ", round(curr_ext$xmax, 6), "] ", "Y [", round(curr_ext$ymin, 6), ", ", round(curr_ext$ymax, 6), "]\n", sep = "") } } if (all_match) { cat(" ✓ All TIFF extents MATCH perfectly!\n") } else { cat(" ⚠️ Extents differ - creating master extent covering all\n") } # Create master extent cat("\n[3] Creating master extent...\n") master_xmin <- min(sapply(extents, function(e) e$xmin)) master_xmax <- max(sapply(extents, function(e) e$xmax)) master_ymin <- min(sapply(extents, function(e) e$ymin)) master_ymax <- max(sapply(extents, function(e) e$ymax)) x_range_m <- (master_xmax - master_xmin) * 111320 y_range_m <- (master_ymax - master_ymin) * 111320 cat(" Master extent: X [", round(master_xmin, 6), ", ", round(master_xmax, 6), "] ", "Y [", round(master_ymin, 6), ", ", round(master_ymax, 6), "]\n", sep = "") cat(" Coverage: ", round(x_range_m / 1000, 1), "km × ", round(y_range_m / 1000, 1), "km\n", sep = "") # Auto-determine grid size based on ROI dimensions if (x_range_m < 10000 && y_range_m < 10000) { cat("\n ⚠️ ROI is small (< 10×10 km). Using single tile (1×1 grid) - no splitting needed!\n") GRID_NROWS <- 1 GRID_NCOLS <- 1 } else { cat("\n ROI size allows tiling. Using 5×5 grid (25 tiles per date).\n") GRID_NROWS <- 5 GRID_NCOLS <- 5 } N_TILES <- GRID_NROWS * GRID_NCOLS # Check if master grid already exists cat("\n[4] Checking if master grid exists...\n") master_grid_file <- file.path(OUTPUT_FOLDER, "master_grid_5x5.geojson") if (file.exists(master_grid_file)) { cat(" ✓ Master grid exists! Loading existing grid...\n") master_grid_sf <- st_read(master_grid_file, quiet = TRUE) master_grid_vect <- terra::vect(master_grid_file) cat(" ✓ Loaded grid with ", nrow(master_grid_sf), " tiles\n", sep = "") } else { cat(" Grid does not exist. Creating new master grid...\n") # Create 5×5 grid cat("\n[5] Creating ", GRID_NCOLS, "×", GRID_NROWS, " master grid...\n", sep = "") master_bbox <- st_bbox(c( xmin = master_xmin, xmax = master_xmax, ymin = master_ymin, ymax = master_ymax ), crs = 4326) bbox_sf <- st_as_sfc(master_bbox) master_grid <- st_make_grid( bbox_sf, n = c(GRID_NCOLS, GRID_NROWS), what = "polygons" ) master_grid_sf <- st_sf( tile_id = sprintf("%02d", 1:length(master_grid)), geometry = master_grid ) cat(" ✓ Created grid with ", length(master_grid), " cells\n", sep = "") # Convert to SpatVector for use in makeTiles master_grid_vect <- terra::vect(master_grid_sf) # Save master grid if (!dir.exists(OUTPUT_FOLDER)) { dir.create(OUTPUT_FOLDER, recursive = TRUE, showWarnings = FALSE) } st_write(master_grid_sf, master_grid_file, delete_dsn = TRUE, quiet = TRUE) cat(" ✓ Master grid saved to: master_grid_5x5.geojson\n") } # ============================================================================ # PART 2: SPLIT EACH TIFF INTO TILES # ============================================================================ cat("\n[PART 2] Splitting TIFFs into Tiles\n") cat("\n[6] Splitting TIFFs using master grid...\n") total_tiles_created <- 0 for (file_idx in seq_along(tiff_files)) { tiff_file <- tiff_files[file_idx] date_str <- gsub("\\.tif$", "", tiff_file) cat("\n Processing: ", tiff_file, "\n", sep = "") # Load TIFF tiff_path <- file.path(TIFF_FOLDER, tiff_file) raster <- terra::rast(tiff_path) dims <- dim(raster) cat(" Dimensions: ", dims[2], "×", dims[1], " pixels\n", sep = "") # Create date-specific output folder date_output_folder <- file.path(OUTPUT_FOLDER, date_str) if (!dir.exists(date_output_folder)) { dir.create(date_output_folder, recursive = TRUE, showWarnings = FALSE) } cat(" Splitting into ", N_TILES, " tiles using master grid...\n", sep = "") # Split using master grid zones tiles_list <- terra::makeTiles( x = raster, y = master_grid_vect, filename = file.path(date_output_folder, "tile.tif"), overwrite = TRUE ) cat(" ✓ Created ", length(tiles_list), " tiles\n", sep = "") # Rename tiles to [DATE]_[TILE_ID].tif cat(" Renaming tiles...\n") for (tile_idx in seq_along(tiles_list)) { source_file <- file.path(date_output_folder, paste0("tile", tile_idx, ".tif")) tile_id <- sprintf("%02d", tile_idx) final_file <- file.path(date_output_folder, paste0(date_str, "_", tile_id, ".tif")) if (file.exists(source_file)) { file.rename(source_file, final_file) } } cat(" ✓ Saved ", N_TILES, " tiles in folder: ", date_str, "/\n", sep = "") total_tiles_created <- total_tiles_created + length(tiles_list) } # ============================================================================ # VERIFICATION # ============================================================================ cat("\n[7] Verifying output...\n") # Count tiles per date folder date_folders <- list.dirs(OUTPUT_FOLDER, full.names = FALSE, recursive = FALSE) date_folders <- sort(date_folders[date_folders != "."]) total_tile_files <- 0 for (date_folder in date_folders) { tiles_in_folder <- list.files(file.path(OUTPUT_FOLDER, date_folder), pattern = "\\.tif$") tiles_in_folder <- tiles_in_folder[!grepl("master_grid", tiles_in_folder)] total_tile_files <- total_tile_files + length(tiles_in_folder) cat(" ", date_folder, ": ", length(tiles_in_folder), " tiles\n", sep = "") } # ============================================================================ # SUMMARY # ============================================================================ cat("SUMMARY\n") cat("\nMaster Grid:\n") cat(" - Dimensions: ", GRID_NCOLS, "×", GRID_NROWS, "=", N_TILES, " tiles\n", sep = "") cat(" - File: master_grid_5x5.geojson\n") cat("\nTIFF Splitting:\n") cat(" - TIFFs processed: ", length(tiff_files), "\n", sep = "") cat(" - Total tile files created: ", total_tile_files, "\n", sep = "") cat(" - Expected total: ", length(tiff_files) * N_TILES, "\n", sep = "") cat("\nDirectory Structure:\n") cat(" daily_tiles/\n") cat(" ├── master_grid_5x5.geojson\n") for (date_folder in date_folders) { cat(" ├── ", date_folder, "/\n", sep = "") cat(" │ ├── ", date_folder, "_01.tif\n", sep = "") cat(" │ ├── ", date_folder, "_02.tif\n", sep = "") cat(" │ └── ...\n") } cat("\nKey Properties:\n") cat(" - All tiles align perfectly across dates\n") cat(" - Tile 01 covers same area in all dates\n") cat(" - Date folders provide organizational hierarchy\n") cat(" - Can do time-series analysis per tile\n") cat("✓ Script complete!\n")