Flood fill to improve performance
This commit is contained in:
@@ -2,6 +2,7 @@ use crate::projection::OrthoProjection;
|
||||
use anyhow::{Context, Result};
|
||||
use font8x8::{UnicodeFonts, BASIC_FONTS};
|
||||
use plotters::prelude::*;
|
||||
use std::collections::VecDeque;
|
||||
use std::path::Path;
|
||||
|
||||
const IMG_WIDTH: u32 = 900;
|
||||
@@ -118,32 +119,58 @@ pub fn render_frame(
|
||||
|
||||
map_area.fill(&LAND_BG).context("fill map area")?;
|
||||
|
||||
// Plot grid points
|
||||
// Nearest-neighbour fill via multi-source BFS.
|
||||
//
|
||||
// Each data point seeds one pixel in a flat grid. BFS then propagates each
|
||||
// value outward to all 4-connected NaN neighbours, so every reachable pixel
|
||||
// ends up holding the value of the closest source point (by Manhattan distance).
|
||||
// Complexity: O(map_w × map_h) — ~410 k array ops, no hashing.
|
||||
let grid_w = map_w as usize;
|
||||
let grid_h = map_h as usize;
|
||||
let mut grid = vec![f32::NAN; grid_w * grid_h];
|
||||
let mut queue: VecDeque<(i32, i32)> = VecDeque::new();
|
||||
|
||||
// Seed the grid with projected data points.
|
||||
for i in 0..lats.len() {
|
||||
let lat = lats[i] as f64;
|
||||
let lon = lons[i] as f64;
|
||||
|
||||
let Some((px, py)) = proj.project(lat, lon) else { continue };
|
||||
let Some((col, row)) = proj.to_pixel(px, py, map_w, map_h) else { continue };
|
||||
|
||||
let cover = cloud_cover[i];
|
||||
if cover.is_nan() {
|
||||
continue; // missing value (bitmap) — keep background
|
||||
continue;
|
||||
}
|
||||
let color = match cloud_color(cover) {
|
||||
Some(c) => c,
|
||||
None => continue, // clear sky — keep land background
|
||||
};
|
||||
let Some((px, py)) = proj.project(lats[i] as f64, lons[i] as f64) else { continue };
|
||||
let Some((col, row)) = proj.to_pixel(px, py, map_w, map_h) else { continue };
|
||||
let idx = row as usize * grid_w + col as usize;
|
||||
if grid[idx].is_nan() {
|
||||
grid[idx] = cover;
|
||||
queue.push_back((col, row));
|
||||
}
|
||||
}
|
||||
|
||||
// Paint a 2×2 block to avoid gaps between grid points
|
||||
for dy in 0..2i32 {
|
||||
for dx in 0..2i32 {
|
||||
let c = col + dx;
|
||||
let r = row + dy;
|
||||
if c >= 0 && c < map_w as i32 && r >= 0 && r < map_h as i32 {
|
||||
map_area.draw_pixel((c, r), &color).ok();
|
||||
}
|
||||
// BFS flood fill.
|
||||
const DIRS: [(i32, i32); 4] = [(-1, 0), (1, 0), (0, -1), (0, 1)];
|
||||
while let Some((col, row)) = queue.pop_front() {
|
||||
let cover = grid[row as usize * grid_w + col as usize];
|
||||
for (dc, dr) in DIRS {
|
||||
let nc = col + dc;
|
||||
let nr = row + dr;
|
||||
if nc < 0 || nc >= map_w as i32 || nr < 0 || nr >= map_h as i32 {
|
||||
continue;
|
||||
}
|
||||
let nidx = nr as usize * grid_w + nc as usize;
|
||||
if grid[nidx].is_nan() {
|
||||
grid[nidx] = cover;
|
||||
queue.push_back((nc, nr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Paint the filled grid.
|
||||
for row in 0..map_h as i32 {
|
||||
for col in 0..map_w as i32 {
|
||||
let cover = grid[row as usize * grid_w + col as usize];
|
||||
if let Some(color) = cloud_color(cover) {
|
||||
map_area.draw_pixel((col, row), &color).ok();
|
||||
}
|
||||
// NaN or clear sky: keep the land background
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user