work
|
@ -6,6 +6,7 @@
|
||||||
<sourceFolder url="file://$MODULE_DIR$/nexrad2/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/nexrad2/src" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/nxar2/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/nxar2/src" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/rtwx/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/rtwx/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/rtwx-desktop/src" isTestSource="false" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
|
|
|
@ -3,7 +3,8 @@ members = [
|
||||||
"nexrad2",
|
"nexrad2",
|
||||||
"rtwx",
|
"rtwx",
|
||||||
"nexrad-browser",
|
"nexrad-browser",
|
||||||
"nxar2"
|
"nxar2",
|
||||||
|
"rtwx-desktop"
|
||||||
]
|
]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
|
|
|
@ -33,10 +33,18 @@ To open RTWX, open [rtwx.e3t.cc](https://rtwx.e3t.cc) in your browser. After a b
|
||||||
|
|
||||||
## The Scope
|
## The Scope
|
||||||
|
|
||||||
After you initially load RTWX, the scope will appear blank. This is because text is hidden by default. To show it, enter the command `` `T `` to toggle `` ` `` text `T`.
|
After you initially load RTWX, the scope will appear blank.
|
||||||
|
|
||||||
|
![Empty Scope](empty_scope.png)
|
||||||
|
|
||||||
|
This is because text is hidden by default. To show it, enter the command `` `T `` to toggle `` ` `` text `T`.
|
||||||
|
|
||||||
|
![Inoperative Scope](scope_inop.png)
|
||||||
|
|
||||||
The scope is broken down into 5 main parts.
|
The scope is broken down into 5 main parts.
|
||||||
|
|
||||||
|
![Marked Up Scope](scope_inop_markedup.png)
|
||||||
|
|
||||||
### Status Information Area
|
### Status Information Area
|
||||||
|
|
||||||
In the top left of the scope is the *Status Information Area.*
|
In the top left of the scope is the *Status Information Area.*
|
||||||
|
@ -69,11 +77,60 @@ The command buffer will contain any commands you are entering and responses to t
|
||||||
|
|
||||||
### Site Information Area
|
### Site Information Area
|
||||||
|
|
||||||
*Reserved*
|
In the top right of the scope is the Site Information Area, which contains information about the currently loaded radar file.
|
||||||
|
|
||||||
|
When inoperative, the Site Information Area will report that all information is "unavailable".
|
||||||
|
|
||||||
|
![Site Information Area: Inoperative](site_information_area_inop.png)
|
||||||
|
|
||||||
|
Once loaded, it will show the following data:
|
||||||
|
|
||||||
|
![Site Information Area: Filled KOTX](site_information_area_kotx.png)
|
||||||
|
|
||||||
|
- the ICAO of the current radar site
|
||||||
|
- the VCP number in use
|
||||||
|
- a plain-language description of the VCP
|
||||||
|
- the site delay: how long ago was the current radar file captured (HH:MM:SS)
|
||||||
|
|
||||||
### Mode Selector
|
### Mode Selector
|
||||||
|
|
||||||
*Reserved*
|
The Mode Selector is located on the midright of the scope. It contains information about the current Mode and Elevation that the scope is displaying.
|
||||||
|
|
||||||
|
The Mode Selector is broken down into two parts:
|
||||||
|
|
||||||
|
#### Radar Product Mode
|
||||||
|
|
||||||
|
The Radar Product Mode display shows which radar product is currently being displayed. While the scope is inoperative, it will display `>RADR INOP<` in place of mode options:
|
||||||
|
|
||||||
|
![Radar Product Mode: Inoperative](mode_inop.png)
|
||||||
|
|
||||||
|
Once radar data is being received, it will show a list of the products available for the currently selected elevation:
|
||||||
|
|
||||||
|
![Radar Product Mode: Filled](mode_filled.png)
|
||||||
|
|
||||||
|
The currently selected product is shown highlighted in white, with angle brackets around it.
|
||||||
|
Typically, `REF` (Reflectivity) will be selected by default.
|
||||||
|
|
||||||
|
Not all products are available for every elevation. For example, most commonly Velocity and Spectrum Width will not be present:
|
||||||
|
|
||||||
|
![Radar Product Mode: Partial](mode_partial.png)
|
||||||
|
|
||||||
|
To change what mode is being displayed, use the `MODE SET` command.
|
||||||
|
|
||||||
|
#### Radar Elevation
|
||||||
|
|
||||||
|
The Radar Elevation display, below the Radar Product Mode display, shows which elevations are available in the current radar data. While the scope is inoperative, it will display `ELEVATION INFO UNAVAILABLE` in place of elevations:
|
||||||
|
|
||||||
|
![Radar Elevation: Inoperative](elevations_inop.png)
|
||||||
|
|
||||||
|
Once radar data is being received, it will show a list of the elevations available:
|
||||||
|
|
||||||
|
![Radar Elevation: Filled](elevations_filled.png)
|
||||||
|
|
||||||
|
The currently selected elevation will be highlighted in white, and have angle brackets around it.
|
||||||
|
Typically, elevation `001` will be selected by default.
|
||||||
|
|
||||||
|
To change which elevation is being displayed, use the `ELEVATION SET` command. Changing elevation will automatically reset the scope to `REF` (Reflectivity) mode.
|
||||||
|
|
||||||
### Radar Scope
|
### Radar Scope
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 7.6 KiB |
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 71 KiB |
After Width: | Height: | Size: 8.4 KiB |
After Width: | Height: | Size: 17 KiB |
|
@ -27,6 +27,7 @@ wgpu = { version = "0.18", features = ["webgl"] }
|
||||||
raw-window-handle = "0.5"
|
raw-window-handle = "0.5"
|
||||||
wasm-bindgen-futures = "0.4"
|
wasm-bindgen-futures = "0.4"
|
||||||
bytemuck = { version = "1", features = ["derive"]}
|
bytemuck = { version = "1", features = ["derive"]}
|
||||||
|
profiling = "1"
|
||||||
|
|
||||||
# Text rendering #
|
# Text rendering #
|
||||||
wgpu_glyph = { git = "https://github.com/hecrj/wgpu_glyph" }
|
wgpu_glyph = { git = "https://github.com/hecrj/wgpu_glyph" }
|
||||||
|
|
|
@ -122,7 +122,7 @@ pub async fn __nxrd_browser_init(w: u32, h: u32) -> AbiProxy {
|
||||||
if event.logical_key == Key::Named(NamedKey::Enter) {
|
if event.logical_key == Key::Named(NamedKey::Enter) {
|
||||||
let command = scope_state.command_buf.clone();
|
let command = scope_state.command_buf.clone();
|
||||||
scope_state.command_buf = String::new();
|
scope_state.command_buf = String::new();
|
||||||
exec(&mut scope_state, command);
|
exec(&mut scope_state, command.replace("\n", " "));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ use nexrad2::Nexrad2Chunk;
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
|
use itertools::Itertools;
|
||||||
use log::info;
|
use log::info;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
|
|
||||||
|
@ -22,9 +23,12 @@ use wgpu_glyph::{GlyphBrush, GlyphBrushBuilder, HorizontalAlign, Layout, Section
|
||||||
use winit::dpi::PhysicalSize;
|
use winit::dpi::PhysicalSize;
|
||||||
use winit::event::WindowEvent;
|
use winit::event::WindowEvent;
|
||||||
use winit::window::Window;
|
use winit::window::Window;
|
||||||
|
use crate::mode::Mode::{RadarInoperative, Reflectivity};
|
||||||
use crate::rendering::colors::rgb_to_srgb;
|
use crate::rendering::colors::rgb_to_srgb;
|
||||||
use crate::rendering::time::zulu;
|
use crate::rendering::time::zulu;
|
||||||
use crate::rendering::vertex::{VERTICES};
|
use crate::rendering::vertex::{VERTICES};
|
||||||
|
use crate::utils::parse_date;
|
||||||
|
use crate::vcp::vcp_string;
|
||||||
|
|
||||||
pub struct ScopeState {
|
pub struct ScopeState {
|
||||||
pub ar2: Option<Nexrad2Chunk>,
|
pub ar2: Option<Nexrad2Chunk>,
|
||||||
|
@ -318,11 +322,11 @@ impl ScopeState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let command_base = (self.wgpu.surface_config.height / 3) as f32;
|
let one_third = (self.wgpu.surface_config.height / 3) as f32;
|
||||||
|
|
||||||
for (line_no, line) in self.command_buf.split('\n').enumerate() {
|
for (line_no, line) in self.command_buf.split('\n').enumerate() {
|
||||||
self.wgpu.glyph_brush.queue(Section {
|
self.wgpu.glyph_brush.queue(Section {
|
||||||
screen_position: (10.0, command_base + (line_height * line_no as f32)),
|
screen_position: (10.0, one_third + (line_height * line_no as f32)),
|
||||||
bounds: (self.wgpu.surface_config.width as f32, self.wgpu.surface_config.height as f32),
|
bounds: (self.wgpu.surface_config.width as f32, self.wgpu.surface_config.height as f32),
|
||||||
text: vec![Text::new(line)
|
text: vec![Text::new(line)
|
||||||
.with_color(rgb_to_srgb(0x32cd32, 1.0))
|
.with_color(rgb_to_srgb(0x32cd32, 1.0))
|
||||||
|
@ -340,6 +344,191 @@ impl ScopeState {
|
||||||
.with_scale(self.prefs.fcs)],
|
.with_scale(self.prefs.fcs)],
|
||||||
..Section::default()
|
..Section::default()
|
||||||
}.with_layout(Layout::default().h_align(HorizontalAlign::Right)));
|
}.with_layout(Layout::default().h_align(HorizontalAlign::Right)));
|
||||||
|
|
||||||
|
if let Some(ar2) = &self.ar2 {
|
||||||
|
self.wgpu.glyph_brush.queue(Section {
|
||||||
|
screen_position: (self.wgpu.surface_config.width as f32 - 10.0, 8.0 + line_height),
|
||||||
|
bounds: (self.wgpu.surface_config.width as f32, self.wgpu.surface_config.height as f32),
|
||||||
|
text: vec![Text::new(&format!("{} VCP {} {}", ar2.volume_header_record.icao,
|
||||||
|
ar2.meta_rda_status_data.vcp,
|
||||||
|
vcp_string(ar2.meta_rda_status_data.vcp)))
|
||||||
|
.with_color(rgb_to_srgb(0x32cd32, 1.0))
|
||||||
|
.with_scale(self.prefs.fcs)],
|
||||||
|
..Section::default()
|
||||||
|
}.with_layout(Layout::default().h_align(HorizontalAlign::Right)));
|
||||||
|
|
||||||
|
let recorded = parse_date(ar2.volume_header_record.date, ar2.volume_header_record.time);
|
||||||
|
let delay = time - recorded;
|
||||||
|
|
||||||
|
let seconds = delay.num_seconds() % 60;
|
||||||
|
let minutes = (delay.num_seconds() / 60) % 60;
|
||||||
|
let hours = delay.num_seconds() / 3600;
|
||||||
|
|
||||||
|
self.wgpu.glyph_brush.queue(Section {
|
||||||
|
screen_position: (self.wgpu.surface_config.width as f32 - 10.0, 8.0 + (line_height*2.0)),
|
||||||
|
bounds: (self.wgpu.surface_config.width as f32, self.wgpu.surface_config.height as f32),
|
||||||
|
text: vec![Text::new(&format!("SITE DELAY {:0>2}:{:0>2}:{:0>2}", hours, minutes, seconds))
|
||||||
|
.with_color(rgb_to_srgb(0x32cd32, 1.0))
|
||||||
|
.with_scale(self.prefs.fcs)],
|
||||||
|
..Section::default()
|
||||||
|
}.with_layout(Layout::default().h_align(HorizontalAlign::Right)));
|
||||||
|
} else {
|
||||||
|
self.wgpu.glyph_brush.queue(Section {
|
||||||
|
screen_position: (self.wgpu.surface_config.width as f32 - 10.0, 8.0 + line_height),
|
||||||
|
bounds: (self.wgpu.surface_config.width as f32, self.wgpu.surface_config.height as f32),
|
||||||
|
text: vec![Text::new("SITE INFORMATION UNAVAILABLE")
|
||||||
|
.with_color(rgb_to_srgb(0x32cd32, 1.0))
|
||||||
|
.with_scale(self.prefs.fcs)],
|
||||||
|
..Section::default()
|
||||||
|
}.with_layout(Layout::default().h_align(HorizontalAlign::Right)));
|
||||||
|
self.wgpu.glyph_brush.queue(Section {
|
||||||
|
screen_position: (self.wgpu.surface_config.width as f32 - 10.0, 8.0 + (line_height * 2.0)),
|
||||||
|
bounds: (self.wgpu.surface_config.width as f32, self.wgpu.surface_config.height as f32),
|
||||||
|
text: vec![Text::new("DELAY INFORMATION UNAVAILABLE")
|
||||||
|
.with_color(rgb_to_srgb(0x32cd32, 1.0))
|
||||||
|
.with_scale(self.prefs.fcs)],
|
||||||
|
..Section::default()
|
||||||
|
}.with_layout(Layout::default().h_align(HorizontalAlign::Right)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// mode info
|
||||||
|
self.wgpu.glyph_brush.queue(Section {
|
||||||
|
screen_position: (self.wgpu.surface_config.width as f32 - 10.0, one_third),
|
||||||
|
bounds: (self.wgpu.surface_config.width as f32, self.wgpu.surface_config.height as f32),
|
||||||
|
text: vec![Text::new("MODE")
|
||||||
|
.with_color(rgb_to_srgb(0x32cd32, 1.0))
|
||||||
|
.with_scale(self.prefs.fcs)],
|
||||||
|
..Section::default()
|
||||||
|
}.with_layout(Layout::default().h_align(HorizontalAlign::Right)));
|
||||||
|
|
||||||
|
let modelines = [
|
||||||
|
[Mode::Reflectivity, Mode::Velocity, Mode::SpectrumWidth].as_slice(),
|
||||||
|
[
|
||||||
|
Mode::DifferentialReflectivity,
|
||||||
|
Mode::DifferentialPhase,
|
||||||
|
Mode::CorrelationCoefficient,
|
||||||
|
]
|
||||||
|
.as_slice(),
|
||||||
|
[Mode::ClutterFilterPowerRemoved, Mode::RadarInoperative].as_slice(),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut available_modes = vec![];
|
||||||
|
|
||||||
|
if let Some(ar2) = &self.ar2 {
|
||||||
|
let types = ar2.elevations.get(&self.selected_elevation).unwrap();
|
||||||
|
available_modes = types[0].available_data.keys().collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (line_no, line) in modelines.iter().enumerate() {
|
||||||
|
let x = (self.wgpu.surface_config.width as f32 - 10.0);
|
||||||
|
let y = one_third + line_height * (line_no as f32 + 1.0);
|
||||||
|
for (item_no, item) in line.iter().enumerate() {
|
||||||
|
let pad_start = item_no;
|
||||||
|
let pad_end = 2 - item_no;
|
||||||
|
let pad_start = " ".repeat(pad_start * 6);
|
||||||
|
let pad_end = " ".repeat(pad_end * 6);
|
||||||
|
let middle = if self.scope_mode == *item {
|
||||||
|
item.selected()
|
||||||
|
} else {
|
||||||
|
item.unselected()
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.scope_mode == *item {
|
||||||
|
// display selected color
|
||||||
|
if *item == RadarInoperative {
|
||||||
|
self.wgpu.glyph_brush.queue(Section {
|
||||||
|
screen_position: (x, y),
|
||||||
|
bounds: (self.wgpu.surface_config.width as f32, self.wgpu.surface_config.height as f32),
|
||||||
|
text: vec![Text::new(">RADR INOP<")
|
||||||
|
.with_color(rgb_to_srgb(0xff0000, 1.0))
|
||||||
|
.with_scale(self.prefs.fcs)],
|
||||||
|
..Section::default()
|
||||||
|
}.with_layout(Layout::default().h_align(HorizontalAlign::Right)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if *item == RadarInoperative {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if available_modes.contains(&&item.rname().to_string()) {
|
||||||
|
self.wgpu.glyph_brush.queue(Section {
|
||||||
|
screen_position: (x, y),
|
||||||
|
bounds: (self.wgpu.surface_config.width as f32, self.wgpu.surface_config.height as f32),
|
||||||
|
text: vec![Text::new(&format!(" {}{}{}", pad_start, middle, pad_end))
|
||||||
|
.with_color(rgb_to_srgb(if self.scope_mode == *item { 0xdedede } else { 0x32cd32 }, 1.0))
|
||||||
|
.with_scale(self.prefs.fcs)],
|
||||||
|
..Section::default()
|
||||||
|
}.with_layout(Layout::default().h_align(HorizontalAlign::Right)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let four_sevenths = ((self.wgpu.surface_config.height / 7) * 4) as f32;
|
||||||
|
|
||||||
|
self.wgpu.glyph_brush.queue(Section {
|
||||||
|
screen_position: (self.wgpu.surface_config.width as f32 - 10.0, four_sevenths),
|
||||||
|
bounds: (self.wgpu.surface_config.width as f32, self.wgpu.surface_config.height as f32),
|
||||||
|
text: vec![Text::new("ELEVATIONS")
|
||||||
|
.with_color(rgb_to_srgb(0x32cd32, 1.0))
|
||||||
|
.with_scale(self.prefs.fcs)],
|
||||||
|
..Section::default()
|
||||||
|
}.with_layout(Layout::default().h_align(HorizontalAlign::Right)));
|
||||||
|
|
||||||
|
if let Some(ar2) = &self.ar2 {
|
||||||
|
let mut line_no = 0;
|
||||||
|
|
||||||
|
for chunk in &ar2
|
||||||
|
.elevations
|
||||||
|
.iter()
|
||||||
|
.sorted_by(|a, b| Ord::cmp(&a.0, &b.0))
|
||||||
|
.enumerate()
|
||||||
|
.chunks(4)
|
||||||
|
{
|
||||||
|
for (no_in_line, (elevation_no, scans)) in chunk {
|
||||||
|
if self.selected_elevation != *elevation_no {
|
||||||
|
let s = &format!(
|
||||||
|
" {:0>3} {}",
|
||||||
|
elevation_no,
|
||||||
|
" ".repeat(5 * (3 - (no_in_line % 4)))
|
||||||
|
);
|
||||||
|
|
||||||
|
self.wgpu.glyph_brush.queue(Section {
|
||||||
|
screen_position: (self.wgpu.surface_config.width as f32 - 10.0, four_sevenths + line_height * (line_no as f32 + 1.0)),
|
||||||
|
bounds: (self.wgpu.surface_config.width as f32, self.wgpu.surface_config.height as f32),
|
||||||
|
text: vec![Text::new(s)
|
||||||
|
.with_color(rgb_to_srgb(0x32cd32, 1.0))
|
||||||
|
.with_scale(self.prefs.fcs)],
|
||||||
|
..Section::default()
|
||||||
|
}.with_layout(Layout::default().h_align(HorizontalAlign::Right)));
|
||||||
|
} else {
|
||||||
|
let s = &format!(
|
||||||
|
">{:0>3}<{}",
|
||||||
|
elevation_no,
|
||||||
|
" ".repeat(5 * (3 - (no_in_line % 4)))
|
||||||
|
);
|
||||||
|
|
||||||
|
self.wgpu.glyph_brush.queue(Section {
|
||||||
|
screen_position: (self.wgpu.surface_config.width as f32 - 10.0, four_sevenths + line_height * (line_no as f32 + 1.0)),
|
||||||
|
bounds: (self.wgpu.surface_config.width as f32, self.wgpu.surface_config.height as f32),
|
||||||
|
text: vec![Text::new(s)
|
||||||
|
.with_color(rgb_to_srgb(0xdedede, 1.0))
|
||||||
|
.with_scale(self.prefs.fcs)],
|
||||||
|
..Section::default()
|
||||||
|
}.with_layout(Layout::default().h_align(HorizontalAlign::Right)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
line_no += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.wgpu.glyph_brush.queue(Section {
|
||||||
|
screen_position: (self.wgpu.surface_config.width as f32 - 10.0, four_sevenths + line_height),
|
||||||
|
bounds: (self.wgpu.surface_config.width as f32, self.wgpu.surface_config.height as f32),
|
||||||
|
text: vec![Text::new("ELEVATION INFO UNAVAILABLE")
|
||||||
|
.with_color(rgb_to_srgb(0x32cd32, 1.0))
|
||||||
|
.with_scale(self.prefs.fcs)],
|
||||||
|
..Section::default()
|
||||||
|
}.with_layout(Layout::default().h_align(HorizontalAlign::Right)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.wgpu.glyph_brush
|
self.wgpu.glyph_brush
|
||||||
|
|
|
@ -18,5 +18,5 @@ fn vs_main(
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
return vec4<f32>(0.3, 0.2, 0.1, 1.0);
|
return vec4<f32>(0.0, 0.0, 0.0, 1.0);
|
||||||
}
|
}
|
|
@ -10,6 +10,7 @@ edition = "2021"
|
||||||
bzip2-rs = { version = "0.1", optional = true }
|
bzip2-rs = { version = "0.1", optional = true }
|
||||||
bzip2 = { version = "0.4", optional = true }
|
bzip2 = { version = "0.4", optional = true }
|
||||||
serde = { version = "1", features = ["derive"], optional = true }
|
serde = { version = "1", features = ["derive"], optional = true }
|
||||||
|
profiling = "1"
|
||||||
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,7 @@ impl Error for NexradParseError {}
|
||||||
|
|
||||||
pub const NEXRAD2_META_CHUNK_FIXED_LENGTH: usize = 325888;
|
pub const NEXRAD2_META_CHUNK_FIXED_LENGTH: usize = 325888;
|
||||||
|
|
||||||
|
#[profiling::function]
|
||||||
pub fn parse_nx2_chunk(cursor: &mut (impl Read + Seek)) -> Result<Nexrad2Chunk, NexradParseError> {
|
pub fn parse_nx2_chunk(cursor: &mut (impl Read + Seek)) -> Result<Nexrad2Chunk, NexradParseError> {
|
||||||
let mut volume_header = [0u8; 24];
|
let mut volume_header = [0u8; 24];
|
||||||
let read = cursor.read(&mut volume_header).map_err(|e| NexradParseError::HeaderReadError(e))?;
|
let read = cursor.read(&mut volume_header).map_err(|e| NexradParseError::HeaderReadError(e))?;
|
||||||
|
|
|
@ -121,6 +121,7 @@ pub struct Message31 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataMoment {
|
impl DataMoment {
|
||||||
|
#[profiling::function]
|
||||||
pub fn scaled_data(&self) -> Vec<f32> {
|
pub fn scaled_data(&self) -> Vec<f32> {
|
||||||
let mut gates = vec![0u16; self.gdm.data_moment_gate_count as usize];
|
let mut gates = vec![0u16; self.gdm.data_moment_gate_count as usize];
|
||||||
|
|
||||||
|
@ -152,6 +153,7 @@ impl DataMoment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[profiling::function]
|
||||||
fn scale_uint(gate: u16, offset: f32, scale: f32) -> f32 {
|
fn scale_uint(gate: u16, offset: f32, scale: f32) -> f32 {
|
||||||
if scale == 0.0 {
|
if scale == 0.0 {
|
||||||
gate as f32
|
gate as f32
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "rtwx-desktop"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
winit = "0.29"
|
||||||
|
simple_logger = "4"
|
||||||
|
log = "0.4"
|
||||||
|
wgpu = "0.18"
|
|
@ -0,0 +1,3 @@
|
||||||
|
fn main() {
|
||||||
|
simple_logger::init_with_env().unwrap();
|
||||||
|
}
|