working on something

This commit is contained in:
core 2025-05-13 11:10:26 -04:00
parent 61f70fae85
commit 06a43bce09
10 changed files with 207 additions and 39 deletions

26
Cargo.lock generated
View file

@ -2871,7 +2871,7 @@ dependencies = [
"log", "log",
"rustc-hash 1.1.0", "rustc-hash 1.1.0",
"spirv", "spirv",
"strum", "strum 0.26.3",
"termcolor", "termcolor",
"thiserror 2.0.12", "thiserror 2.0.12",
"unicode-xid", "unicode-xid",
@ -4556,9 +4556,15 @@ version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
dependencies = [ dependencies = [
"strum_macros", "strum_macros 0.26.4",
] ]
[[package]]
name = "strum"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
[[package]] [[package]]
name = "strum_macros" name = "strum_macros"
version = "0.26.4" version = "0.26.4"
@ -4572,6 +4578,19 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "strum_macros"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
[[package]] [[package]]
name = "subtle" name = "subtle"
version = "2.6.1" version = "2.6.1"
@ -6307,11 +6326,14 @@ dependencies = [
"rayon", "rayon",
"reqwest", "reqwest",
"serde", "serde",
"strum 0.27.1",
"strum_macros 0.27.1",
"tokio", "tokio",
"toml", "toml",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"wxbox-ar2", "wxbox-ar2",
"wxbox-common",
"wxbox-grib2", "wxbox-grib2",
"wxbox-pal", "wxbox-pal",
] ]

View file

@ -1,12 +1,15 @@
/*
var cacheName = 'egui-template-pwa'; var cacheName = 'egui-template-pwa';
*/
/*
var filesToCache = [ var filesToCache = [
'./', './',
'./index.html', './index.html',
'./eframe_template.js', './eframe_template.js',
'./eframe_template_bg.wasm', './eframe_template_bg.wasm',
]; ];
*/
/* Start the service worker and cache all of the app's content */ /* Start the service worker and cache all of the app's content *//*
self.addEventListener('install', function (e) { self.addEventListener('install', function (e) {
e.waitUntil( e.waitUntil(
caches.open(cacheName).then(function (cache) { caches.open(cacheName).then(function (cache) {
@ -14,12 +17,13 @@ self.addEventListener('install', function (e) {
}) })
); );
}); });
*/
/* Serve cached content when offline */ /* Serve cached content when offline *//*
self.addEventListener('fetch', function (e) { self.addEventListener('fetch', function (e) {
e.respondWith( e.respondWith(
caches.match(e.request).then(function (response) { caches.match(e.request).then(function (response) {
return response || fetch(e.request); return response || fetch(e.request);
}) })
); );
}); });
*/

View file

@ -88,7 +88,7 @@ impl eframe::App for App {
&mut self.selected_layer, &mut self.selected_layer,
); );
} }
//right_bar(ctx); //right_bar(ctx, self);
egui::CentralPanel::default().show(ctx, |ui| { egui::CentralPanel::default().show(ctx, |ui| {
ui.add(walkers::Map::new( ui.add(walkers::Map::new(

View file

@ -14,6 +14,8 @@ use egui::{
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use tracing::debug; use tracing::debug;
use crate::map::sources::baselayers::BASELAYER_OSM;
use crate::map::sources::datalayers::{NOAA_MRMS_MERGED_CREF_QC_CONUS, NOAA_MRMS_MERGED_RHOHV_3KM_CONUS};
fn outer_rect(f: &Prepared) -> Rect { fn outer_rect(f: &Prepared) -> Rect {
let content_rect = f.content_ui.min_rect(); let content_rect = f.content_ui.min_rect();
@ -102,6 +104,33 @@ pub fn main_menu(
}, },
); );
let mut add = |id| {
layer_manager.active_layers.insert(0, ActiveLayer {
source_id: id,
layer_id: LayerId::new(),
visible: true,
});
*add_open = false;
};
ui.collapsing("Baselayers", |ui| {
if ui.button("OpenStreetMap").clicked() {
add(BASELAYER_OSM.source_id);
}
});
ui.collapsing("Datalayers", |ui| {
ui.collapsing("NOAA / MRMS", |ui| {
ui.collapsing("Continental US", |ui| {
for layer in &[&NOAA_MRMS_MERGED_CREF_QC_CONUS, &NOAA_MRMS_MERGED_RHOHV_3KM_CONUS] {
if ui.button(&layer.display_name).clicked() {
add(layer.source_id);
}
}
});
});
});
/*
for (id, registered_layer) in &layer_manager.registered_sources { for (id, registered_layer) in &layer_manager.registered_sources {
// ghost button // ghost button
@ -221,6 +250,8 @@ pub fn main_menu(
} }
frame.paint(ui); frame.paint(ui);
} }
*/
}); });
} }
} }

View file

@ -1,7 +1,8 @@
use crate::ui::shell::bars::pane_header; use crate::ui::shell::bars::pane_header;
use egui::{Align, Direction, Frame, Layout, RichText}; use egui::{Align, Direction, FontFamily, Frame, Layout, RichText, Ui};
use crate::app::App;
pub fn right_bar(ctx: &egui::Context) { pub fn right_bar(ctx: &egui::Context, app: &mut App) {
let mut frame = Frame::side_top_panel(&ctx.style()); let mut frame = Frame::side_top_panel(&ctx.style());
frame.inner_margin.top = 4; frame.inner_margin.top = 4;
frame.inner_margin.left = 0; frame.inner_margin.left = 0;
@ -10,19 +11,67 @@ pub fn right_bar(ctx: &egui::Context) {
egui::SidePanel::right("right_panel") egui::SidePanel::right("right_panel")
.frame(frame) .frame(frame)
.show(ctx, |ui| { .show(ctx, |ui| {
pane_header( if let Some(selected_layer_id) = app.selected_layer {
ui, if let Some(active_layer) = app.layer_manager.active_layers.iter().find(|u| u.layer_id == selected_layer_id) {
"Properties", if let Some(source) = app.layer_manager.registered_sources.get(&active_layer.source_id) {
Some(egui_phosphor::regular::INFO), pane_header(
false, ui,
|ui| {}, &source.display_name,
); Some(source.type_hint.icon()),
false,
|ui| {}
);
ui.with_layout(Layout::top_down_justified(Align::Center), |ui| { egui::Grid::new("properties")
ui.label( .num_columns(2)
RichText::new("Select a layer in the Layers panel to modify it's properties") .spacing([40.0, 4.0])
.italics(), .striped(true)
.show(ui, |ui| {
let mut draw_row = |title, content: Box<dyn Fn(&mut Ui)>| {
ui.horizontal(|ui| {
ui.add_space(8.0);
ui.label(
RichText::new(title)
.family(FontFamily::Name("semibold".into()))
.strong(),
);
});
ui.horizontal(|ui| {
content(ui);
ui.add_space(ui.available_width().max(8.0));
});
ui.end_row();
};
draw_row("Source", Box::new(|ui: &mut Ui| {
ui.label(&source.source);
}));
draw_row("Coverage", Box::new(|ui: &mut Ui| {
ui.label(&source.location);
}));
});
}
}
} else {
pane_header(
ui,
"Properties",
Some(egui_phosphor::regular::INFO),
false,
|ui| {},
); );
});
ui.horizontal_centered(|ui| {
ui.label(
RichText::new("Select a layer in the Layers panel to modify it's properties")
.italics(),
);
});
}
}); });
} }

View file

@ -1,3 +1,4 @@
use std::fmt::Debug;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -13,3 +14,34 @@ impl Default for TileRequestOptions {
} }
} }
} }
#[derive(Deserialize, Serialize)]
pub struct GribTileMetadata {
pub message_time: GribMessageTimeMetadata,
pub source_configuration: Grib2DataSource
}
#[derive(Deserialize, Serialize)]
pub struct GribMessageTimeMetadata {
pub reference_time_significance: u8,
pub year: u16,
pub month: u8,
pub day: u8,
pub hour: u8,
pub minute: u8,
pub second: u8,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct Grib2DataSource {
pub from: String,
pub needs_gzip: bool,
pub valid_for: usize,
pub palette: String,
pub missing: Option<f64>,
pub no_coverage: Option<f64>,
pub range_folded: Option<f64>,
}
impl Debug for Grib2DataSource {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<grib2 data source>")
}
}

View file

@ -36,4 +36,9 @@ wxbox-pal = { version = "0.1", path = "../pal" }
# nexrad # nexrad
geographiclib = "0.1" geographiclib = "0.1"
rayon = "1.10" rayon = "1.10"
strum = "0.27"
strum_macros = "0.27"
# meta
wxbox-common = { path = "../common" }

View file

@ -15,7 +15,7 @@ Color: 80 128 128 128
missing = -99.0 missing = -99.0
no_coverage = -999.0 no_coverage = -999.0
[data.nexrad.kcrp_ref_test] [data.nexrad.l2_reflectivity]
from = "aaaa" from = "aaaa"
palette = """ palette = """
Color: 5 0x40 0xe8 0xe3 Color: 5 0x40 0xe8 0xe3

View file

@ -18,6 +18,7 @@ use std::io;
use std::io::{Cursor, ErrorKind}; use std::io::{Cursor, ErrorKind};
use std::num::TryFromIntError; use std::num::TryFromIntError;
use std::sync::Arc; use std::sync::Arc;
use axum::Json;
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
use tracing::{debug, info_span}; use tracing::{debug, info_span};
use wxbox_grib2::GribMessage; use wxbox_grib2::GribMessage;
@ -25,25 +26,48 @@ use wxbox_grib2::wgs84::LatLong;
use wxbox_pal::{ColorPalette, Palette}; use wxbox_pal::{ColorPalette, Palette};
use rayon::iter::ParallelIterator; use rayon::iter::ParallelIterator;
use wxbox_common::{Grib2DataSource, GribMessageTimeMetadata, GribTileMetadata};
pub type Grib2DataCache = Cache<DataId, Arc<GribMessage>>; pub type Grib2DataCache = Cache<DataId, Arc<GribMessage>>;
pub type Grib2TileCache = Cache<TileId, Arc<Vec<u8>>>; pub type Grib2TileCache = Cache<TileId, Arc<Vec<u8>>>;
pub type Grib2DataConfig = HashMap<String, Grib2DataSource>; pub type Grib2DataConfig = HashMap<String, Grib2DataSource>;
#[derive(Serialize, Deserialize, Clone)] #[tracing::instrument(level = "info")]
pub struct Grib2DataSource { pub async fn grib2_metadata(
pub from: String, Path((source)): Path<(String)>,
pub needs_gzip: bool, State(state): State<AppState>,
pub valid_for: usize, ) -> Result<Json<wxbox_common::GribTileMetadata>, AppError> {
pub palette: String, // is this even a valid data source?
pub missing: Option<f64>, let data_id = DataId {
pub no_coverage: Option<f64>, source,
pub range_folded: Option<f64>, };
} let Some(ds) = state.config.data.grib2.get(&data_id.source) else {
impl Debug for Grib2DataSource { return Err(anyhow!("invalid/unknown grib2 state").into());
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { };
write!(f, "<grib2 data source>")
} // ok, so we don't have a tile image yet
// this means we are going to have to kick off a task to put that in the cache
// lets check if we have the raw data
let data = if !state.grib2_data_cache.contains_key(&data_id) {
// we don't, so let's start by starting a task for that
load_grib2_data(state.grib2_data_cache, data_id, ds.clone()).await?
} else {
state.grib2_data_cache.get(&data_id).await.unwrap()
};
Ok(Json(GribTileMetadata {
message_time: GribMessageTimeMetadata {
reference_time_significance: data.identification.reference_time_significance,
year: data.identification.year,
month: data.identification.month,
day: data.identification.day,
hour: data.identification.hour,
minute: data.identification.minute,
second: data.identification.second,
},
source_configuration: ds.clone(),
}))
} }
#[tracing::instrument(level = "info")] #[tracing::instrument(level = "info")]

View file

@ -5,7 +5,7 @@ mod nexrad;
mod tiles; mod tiles;
use crate::config::Config; use crate::config::Config;
use crate::grib2::{Grib2DataCache, Grib2TileCache, grib2_handler}; use crate::grib2::{Grib2DataCache, Grib2TileCache, grib2_handler, grib2_metadata};
use crate::nexrad::{NexradDataCache, NexradTileCache, nexrad_handler}; use crate::nexrad::{NexradDataCache, NexradTileCache, nexrad_handler};
use crate::tiles::{DataId, TileId}; use crate::tiles::{DataId, TileId};
use axum::Router; use axum::Router;
@ -60,6 +60,7 @@ async fn main() -> anyhow::Result<()> {
let app = Router::new() let app = Router::new()
.route("/grib2/{source}/{z}/{x}/{y}", get(grib2_handler)) .route("/grib2/{source}/{z}/{x}/{y}", get(grib2_handler))
.route("/grib2/{source}/metadata", get(grib2_metadata))
.route("/nexrad/{source}/{z}/{x}/{y}", get(nexrad_handler)) .route("/nexrad/{source}/{z}/{x}/{y}", get(nexrad_handler))
.with_state(state); .with_state(state);