module BomRadarRender
BomRadarRender — polar projection, town overlays, and ASCII rain map rendering. Public: lat_lon_to_cell, render_map Depends: bom_radar_image, bom_radar_towns, geo_lookup, geocoder Tests: test/lib/bom_radar_render_test.rb
Public Instance Methods
Source
# File lib/bom_radar_render.rb, line 34 def image_cell_to_map_cell(image_row, image_col, map_width: BomRadarConfig::MAP_WIDTH, map_height: BomRadarConfig::MAP_HEIGHT) row = (image_row * map_height.to_f / BomRadarConfig::IMAGE_SIZE).floor.clamp(0, map_height - 1) col = (image_col * map_width.to_f / BomRadarConfig::IMAGE_SIZE).floor.clamp(0, map_width - 1) [row, col] end
Source
# File lib/bom_radar_render.rb, line 18 def image_pixel_for(lat, lon, site:) centre = [site[:lat], site[:lon]] distance_km = GeoLookup.distance_km(centre, [lat, lon]) return nil if distance_km > site[:range_km] bearing = Geocoder::Calculations.bearing_between(centre, [lat, lon]) fraction = distance_km / site[:range_km].to_f radius_px = fraction * (BomRadarConfig::IMAGE_SIZE / 2.0 - 1.0) radians = bearing * Math::PI / 180.0 centre_px = BomRadarConfig::IMAGE_SIZE / 2.0 col = centre_px + Math.sin(radians) * radius_px row = centre_px - Math.cos(radians) * radius_px [row.round.clamp(0, BomRadarConfig::IMAGE_SIZE - 1), col.round.clamp(0, BomRadarConfig::IMAGE_SIZE - 1)] end
Source
# File lib/bom_radar_render.rb, line 41 def lat_lon_to_cell(lat, lon, site:, map_width: BomRadarConfig::MAP_WIDTH, map_height: BomRadarConfig::MAP_HEIGHT) pixel = image_pixel_for(lat, lon, site: site) return nil unless pixel image_cell_to_map_cell(pixel[0], pixel[1], map_width: map_width, map_height: map_height) end
Source
# File lib/bom_radar_render.rb, line 49 def overlay_label(grid, row, col, label) text = label.to_s[0, 6] return if text.empty? width = grid.first.length start_col = [col - (text.length / 2), 0].max end_col = [start_col + text.length - 1, width - 1].min actual = text[0, end_col - start_col + 1] actual.chars.each_with_index do |char, index| target_col = start_col + index next if target_col >= width next if grid[row][target_col].match?(/[A-Za-z+]/) grid[row][target_col] = char end end
Source
# File lib/bom_radar_render.rb, line 67 def place_town_labels(char_grid, site:, product_id:) BomRadarTowns.for_product(product_id).each do |town| cell = lat_lon_to_cell(town[:lat], town[:lon], site: site) next unless cell row, col = cell overlay_label(char_grid, row, col, "+#{town[:name]}") end char_grid end
Source
# File lib/bom_radar_render.rb, line 91 def render_map(grid_data, site:, product_id:, query_lat: nil, query_lon: nil, background_data: nil) composite = !background_data.nil? downsampled = if composite BomRadarComposite.downsample(background: background_data, rain: grid_data) else BomRadarImage.downsample(grid_data) end char_grid = downsampled.map(&:dup) center = nil if query_lat && query_lon cell = lat_lon_to_cell(query_lat, query_lon, site: site) center = cell if cell end char_fn = composite ? BomRadarImage.method(:char_for_merged) : BomRadarImage.method(:char_for_index) char_grid = char_grid.map { |row| row.map { |index| char_fn.call(index) } } place_town_labels(char_grid, site: site, product_id: product_id) if center row, col = center char_grid[row][col] = BomRadarConfig::CENTER_CHAR end lines = char_grid.map(&:join) colored = BomRadarImage.colorize_lines(lines, grid: downsampled, center: center, merged: composite) summaries = town_summaries(grid_data, site: site, product_id: product_id) { lines: colored, summaries: summaries, downsampled: downsampled, center: center } end
Source
# File lib/bom_radar_render.rb, line 78 def town_summaries(grid, site:, product_id:) BomRadarTowns.for_product(product_id).filter_map do |town| pixel = image_pixel_for(town[:lat], town[:lon], site: site) next unless pixel index = grid[:grid][pixel[0]][pixel[1]] intensity = BomRadarImage.display_intensity(index) next unless intensity "+#{town[:name]} — #{intensity}" end end