working on something
This commit is contained in:
parent
61f70fae85
commit
06a43bce09
10 changed files with 207 additions and 39 deletions
26
Cargo.lock
generated
26
Cargo.lock
generated
|
@ -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",
|
||||
]
|
||||
|
|
|
@ -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);
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
*/
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
*/
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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>")
|
||||
}
|
||||
}
|
|
@ -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" }
|
|
@ -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
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue