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",
"rustc-hash 1.1.0",
"spirv",
"strum",
"strum 0.26.3",
"termcolor",
"thiserror 2.0.12",
"unicode-xid",
@ -4556,9 +4556,15 @@ version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
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]]
name = "strum_macros"
version = "0.26.4"
@ -4572,6 +4578,19 @@ dependencies = [
"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]]
name = "subtle"
version = "2.6.1"
@ -6307,11 +6326,14 @@ dependencies = [
"rayon",
"reqwest",
"serde",
"strum 0.27.1",
"strum_macros 0.27.1",
"tokio",
"toml",
"tracing",
"tracing-subscriber",
"wxbox-ar2",
"wxbox-common",
"wxbox-grib2",
"wxbox-pal",
]

View file

@ -1,12 +1,15 @@
/*
var cacheName = 'egui-template-pwa';
*/
/*
var filesToCache = [
'./',
'./index.html',
'./eframe_template.js',
'./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) {
e.waitUntil(
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) {
e.respondWith(
caches.match(e.request).then(function (response) {
return response || fetch(e.request);
})
);
});
});
*/

View file

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

View file

@ -14,6 +14,8 @@ use egui::{
use std::collections::HashMap;
use std::sync::Arc;
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 {
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 {
// ghost button
@ -221,6 +250,8 @@ pub fn main_menu(
}
frame.paint(ui);
}
*/
});
}
}

View file

@ -1,7 +1,8 @@
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());
frame.inner_margin.top = 4;
frame.inner_margin.left = 0;
@ -10,19 +11,67 @@ pub fn right_bar(ctx: &egui::Context) {
egui::SidePanel::right("right_panel")
.frame(frame)
.show(ctx, |ui| {
pane_header(
ui,
"Properties",
Some(egui_phosphor::regular::INFO),
false,
|ui| {},
);
if let Some(selected_layer_id) = app.selected_layer {
if let Some(active_layer) = app.layer_manager.active_layers.iter().find(|u| u.layer_id == selected_layer_id) {
if let Some(source) = app.layer_manager.registered_sources.get(&active_layer.source_id) {
pane_header(
ui,
&source.display_name,
Some(source.type_hint.icon()),
false,
|ui| {}
);
ui.with_layout(Layout::top_down_justified(Align::Center), |ui| {
ui.label(
RichText::new("Select a layer in the Layers panel to modify it's properties")
.italics(),
egui::Grid::new("properties")
.num_columns(2)
.spacing([40.0, 4.0])
.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};
#[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
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
no_coverage = -999.0
[data.nexrad.kcrp_ref_test]
[data.nexrad.l2_reflectivity]
from = "aaaa"
palette = """
Color: 5 0x40 0xe8 0xe3

View file

@ -18,6 +18,7 @@ use std::io;
use std::io::{Cursor, ErrorKind};
use std::num::TryFromIntError;
use std::sync::Arc;
use axum::Json;
use tokio::io::AsyncReadExt;
use tracing::{debug, info_span};
use wxbox_grib2::GribMessage;
@ -25,25 +26,48 @@ use wxbox_grib2::wgs84::LatLong;
use wxbox_pal::{ColorPalette, Palette};
use rayon::iter::ParallelIterator;
use wxbox_common::{Grib2DataSource, GribMessageTimeMetadata, GribTileMetadata};
pub type Grib2DataCache = Cache<DataId, Arc<GribMessage>>;
pub type Grib2TileCache = Cache<TileId, Arc<Vec<u8>>>;
pub type Grib2DataConfig = HashMap<String, Grib2DataSource>;
#[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>")
}
#[tracing::instrument(level = "info")]
pub async fn grib2_metadata(
Path((source)): Path<(String)>,
State(state): State<AppState>,
) -> Result<Json<wxbox_common::GribTileMetadata>, AppError> {
// is this even a valid data source?
let data_id = DataId {
source,
};
let Some(ds) = state.config.data.grib2.get(&data_id.source) else {
return Err(anyhow!("invalid/unknown grib2 state").into());
};
// 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")]

View file

@ -5,7 +5,7 @@ mod nexrad;
mod tiles;
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::tiles::{DataId, TileId};
use axum::Router;
@ -60,6 +60,7 @@ async fn main() -> anyhow::Result<()> {
let app = Router::new()
.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))
.with_state(state);