looks like i am going to rewrite the entire rendering engine again
This commit is contained in:
parent
4b7ec8c058
commit
313dca0483
|
@ -0,0 +1,206 @@
|
||||||
|
use nexrad2::message31::MOMENT_DATA_FOLDED;
|
||||||
|
use crate::mode::Mode;
|
||||||
|
|
||||||
|
pub fn correlation_coefficient(val: f32) -> &'static str {
|
||||||
|
let gradient = [
|
||||||
|
(0.275, "black"),
|
||||||
|
(0.35, "darkgrey"),
|
||||||
|
(0.4, "gray"),
|
||||||
|
(0.5, "silver"),
|
||||||
|
(0.6, "midnightblue"),
|
||||||
|
(0.7, "darkblue"),
|
||||||
|
(0.8, "blue"),
|
||||||
|
(0.91, "green"),
|
||||||
|
(0.92, "yellowgreen"),
|
||||||
|
(0.93, "olivedrab"),
|
||||||
|
(0.94, "yellow"),
|
||||||
|
(0.95, "gold"),
|
||||||
|
(0.96, "orange"),
|
||||||
|
(0.97, "orangered"),
|
||||||
|
(0.98, "red"),
|
||||||
|
(0.99, "firebrick"),
|
||||||
|
(1.0, "maroon"),
|
||||||
|
(1.01, "darkmagenta"),
|
||||||
|
(1.02, "purple"),
|
||||||
|
(1.03, "mediumvioletred"),
|
||||||
|
(1.045, "pink"),
|
||||||
|
(1.05, "lavenderblush")
|
||||||
|
];
|
||||||
|
|
||||||
|
for (threshold, color) in gradient {
|
||||||
|
if val < threshold {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"white"
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spectrum_width(val: f32) -> &'static str {
|
||||||
|
let gradient = [
|
||||||
|
(1.0, "black"),
|
||||||
|
(2.0, "#222222"),
|
||||||
|
(3.0, "#333333"),
|
||||||
|
(4.0, "#444444"),
|
||||||
|
(5.0, "#555555"),
|
||||||
|
(6.0, "#666666"),
|
||||||
|
(7.0, "#777777"),
|
||||||
|
(8.0, "#888888"),
|
||||||
|
(9.0, "#999999"),
|
||||||
|
(10.0, "burlywood"),
|
||||||
|
(11.0, "sandybrown"),
|
||||||
|
(12.0, "gold"),
|
||||||
|
(13.0, "orange"),
|
||||||
|
(15.0, "orangered"),
|
||||||
|
(17.0, "red"),
|
||||||
|
(19.0, "firebrick"),
|
||||||
|
(23.0, "darkred"),
|
||||||
|
(25.0, "hotpink"),
|
||||||
|
(27.0, "fuchsia"),
|
||||||
|
(30.0, "lavender"),
|
||||||
|
(32.0, "white"),
|
||||||
|
(35.0, "yellow"),
|
||||||
|
(60.0, "lime"),
|
||||||
|
(1000.0, "purple")
|
||||||
|
];
|
||||||
|
|
||||||
|
for (threshold, color) in gradient {
|
||||||
|
if val < threshold {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"white"
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn differential_reflectivity(val: f32) -> &'static str {
|
||||||
|
let gradient = [
|
||||||
|
(-3.0, "black"),
|
||||||
|
(-1.0, "#333333"),
|
||||||
|
(-0.5, "#666666"),
|
||||||
|
(0.1, "#999999"),
|
||||||
|
(0.0, "#cccccc"),
|
||||||
|
(0.1, "white"),
|
||||||
|
(0.25, "navy"),
|
||||||
|
(0.5, "blue"),
|
||||||
|
(0.75, "deepskyblue"),
|
||||||
|
(1.0, "cyan"),
|
||||||
|
(1.25, "mediumaquamarine"),
|
||||||
|
(1.5, "lime"),
|
||||||
|
(1.75, "yellowgreen"),
|
||||||
|
(2.0, "yellow"),
|
||||||
|
(2.5, "gold"),
|
||||||
|
(3.0, "orange"),
|
||||||
|
(4.0, "orangered"),
|
||||||
|
(5.0, "red"),
|
||||||
|
(6.0, "maroon"),
|
||||||
|
(7.0, "hotpink"),
|
||||||
|
(10.0, "pink"),
|
||||||
|
(999.0, "white")
|
||||||
|
];
|
||||||
|
|
||||||
|
for (threshold, color) in gradient {
|
||||||
|
if val < threshold {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"white"
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dbz_noaa(dbz: f32) -> &'static str {
|
||||||
|
if dbz < 5.0 || dbz == MOMENT_DATA_FOLDED {
|
||||||
|
"#000000"
|
||||||
|
} else if dbz >= 5.0 && dbz < 10.0 {
|
||||||
|
"#40e8e3"
|
||||||
|
} else if dbz >= 10.0 && dbz < 15.0 {
|
||||||
|
"#26a4fa"
|
||||||
|
} else if dbz >= 15.0 && dbz < 20.0 {
|
||||||
|
"#0030ed"
|
||||||
|
} else if dbz >= 20.0 && dbz < 25.0 {
|
||||||
|
"#49fb3e"
|
||||||
|
} else if dbz >= 25.0 && dbz < 30.0 {
|
||||||
|
"#36c22e"
|
||||||
|
} else if dbz >= 30.0 && dbz < 35.0 {
|
||||||
|
"#278c1e"
|
||||||
|
} else if dbz >= 35.0 && dbz < 40.0 {
|
||||||
|
"#fef543"
|
||||||
|
} else if dbz >= 40.0 && dbz < 45.0 {
|
||||||
|
"#ebb433"
|
||||||
|
} else if dbz >= 45.0 && dbz < 50.0 {
|
||||||
|
"#f6952e"
|
||||||
|
} else if dbz >= 50.0 && dbz < 55.0 {
|
||||||
|
"#f80a26"
|
||||||
|
} else if dbz >= 55.0 && dbz < 60.0 {
|
||||||
|
"#cb0516"
|
||||||
|
} else if dbz >= 60.0 && dbz < 65.0 {
|
||||||
|
"#a90813"
|
||||||
|
} else if dbz >= 65.0 && dbz < 70.0 {
|
||||||
|
"#ee34fa"
|
||||||
|
} else if dbz >= 79.0 && dbz < 75.0 {
|
||||||
|
"#9161c4"
|
||||||
|
} else {
|
||||||
|
"#ffffff"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn velocity(vel: f32) -> &'static str {
|
||||||
|
if vel == MOMENT_DATA_FOLDED {
|
||||||
|
return "#691ac1";
|
||||||
|
}
|
||||||
|
|
||||||
|
let colors = [
|
||||||
|
"#F91473", // 140
|
||||||
|
"#AA1079", // 130
|
||||||
|
"#6E0E80", // 120
|
||||||
|
"#2E0E84", // 110
|
||||||
|
"#151F93", // 100
|
||||||
|
"#236FB3", // 90
|
||||||
|
"#41DADB", // 80
|
||||||
|
"#66E1E2", // 70
|
||||||
|
"#9EE8EA", // 60
|
||||||
|
"#57FA63", // 50
|
||||||
|
"#31E32B", // 40
|
||||||
|
// "#21BE0A", // 35
|
||||||
|
"#24AA1F", // 30
|
||||||
|
"#197613", // 20
|
||||||
|
"#456742", // -10
|
||||||
|
"#634F50", // 0
|
||||||
|
"#6e2e39", // 10
|
||||||
|
"#7F030C", // 20
|
||||||
|
"#B60716", // 30
|
||||||
|
// "#C5000D", // 35
|
||||||
|
"#F32245", // 40
|
||||||
|
"#F6508A", // 50
|
||||||
|
"#FB8BBF", // 60
|
||||||
|
"#FDDE93", // 70
|
||||||
|
"#FCB470", // 80
|
||||||
|
"#FA814B", // 90
|
||||||
|
"#DD603C", // 100
|
||||||
|
"#B7452D", // 110
|
||||||
|
"#932C20", // 120
|
||||||
|
"#711614", // 130
|
||||||
|
"#520106", // 140
|
||||||
|
];
|
||||||
|
|
||||||
|
let i = scale_int((vel.floor()) as i32, 140, -140, (colors.len() - 1) as i32, 0);
|
||||||
|
|
||||||
|
colors[i as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scale_int(val: i32, o_max: i32, o_min: i32, n_max: i32, n_min: i32) -> i32 {
|
||||||
|
(((val - o_min) * n_max - n_min) / o_max - o_min) + n_min
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn color_scheme(product: Mode, value: f32) -> &'static str {
|
||||||
|
match product {
|
||||||
|
Mode::Reflectivity => dbz_noaa(value),
|
||||||
|
Mode::Velocity => velocity(value),
|
||||||
|
Mode::SpectrumWidth => spectrum_width(value),
|
||||||
|
Mode::DifferentialReflectivity => differential_reflectivity(value),
|
||||||
|
Mode::DifferentialPhase => correlation_coefficient(value),
|
||||||
|
Mode::CorrelationCoefficient => correlation_coefficient(value),
|
||||||
|
Mode::ClutterFilterPowerRemoved => dbz_noaa(value),
|
||||||
|
Mode::RadarInoperative => "#ff0000"
|
||||||
|
}
|
||||||
|
}
|
|
@ -79,6 +79,8 @@ pub fn exec(state: &mut ScopeState, command: String) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if command == "`T" {
|
||||||
|
state.show_ui = !state.show_ui;
|
||||||
} else {
|
} else {
|
||||||
state.command_buf = "UNRECOGNIZED COMMAND".to_string();
|
state.command_buf = "UNRECOGNIZED COMMAND".to_string();
|
||||||
state.command_buf_response_mode = true;
|
state.command_buf_response_mode = true;
|
||||||
|
|
|
@ -6,6 +6,7 @@ pub mod equirectangular;
|
||||||
pub mod sites;
|
pub mod sites;
|
||||||
pub mod command;
|
pub mod command;
|
||||||
pub mod vcp;
|
pub mod vcp;
|
||||||
|
pub mod colors;
|
||||||
|
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
@ -63,7 +64,8 @@ pub fn __nxrd_browser_init() -> AbiScopeState {
|
||||||
command_buf: String::new(),
|
command_buf: String::new(),
|
||||||
command_buf_response_mode: false,
|
command_buf_response_mode: false,
|
||||||
new_data_available: false,
|
new_data_available: false,
|
||||||
selected_elevation: 1
|
selected_elevation: 1,
|
||||||
|
show_ui: false
|
||||||
};
|
};
|
||||||
|
|
||||||
info!("nexrad-browser initialized successfully");
|
info!("nexrad-browser initialized successfully");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
pub enum Mode {
|
pub enum Mode {
|
||||||
/// REF
|
/// REF
|
||||||
Reflectivity,
|
Reflectivity,
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
|
use std::f64::consts::PI;
|
||||||
use chrono::{DateTime, Timelike, Utc};
|
use chrono::{DateTime, Timelike, Utc};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use log::info;
|
use log::{debug, info};
|
||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
|
use nexrad2::message31::MOMENT_DATA_BELOW_THRESHOLD;
|
||||||
|
use crate::colors::color_scheme;
|
||||||
use crate::mode::Mode;
|
use crate::mode::Mode;
|
||||||
use crate::mode::Mode::{ClutterFilterPowerRemoved, CorrelationCoefficient, DifferentialPhase, DifferentialReflectivity, RadarInoperative, Reflectivity, SpectrumWidth, Velocity};
|
use crate::mode::Mode::{ClutterFilterPowerRemoved, CorrelationCoefficient, DifferentialPhase, DifferentialReflectivity, RadarInoperative, Reflectivity, SpectrumWidth, Velocity};
|
||||||
use crate::rescaleCanvas;
|
use crate::rescaleCanvas;
|
||||||
|
@ -48,8 +51,8 @@ pub fn render(state: &mut ScopeState) -> Result<(), JsValue> {
|
||||||
ctx.set_fill_style(&JsValue::from_str(TEXT_COLOR_GREEN));
|
ctx.set_fill_style(&JsValue::from_str(TEXT_COLOR_GREEN));
|
||||||
|
|
||||||
// render out the scope id line
|
// render out the scope id line
|
||||||
|
if state.show_ui {
|
||||||
ctx.fill_text(&format!("NEXRAD {} {}", state.ar2.as_ref().map(|u| u.volume_header_record.icao.as_str()).unwrap_or("INOP"), zulu(time)), 50.0, 50.0)?;
|
ctx.fill_text(&format!("NEXRAD {} {}", state.ar2.as_ref().map(|u| u.volume_header_record.icao.as_str()).unwrap_or("INOP"), zulu(time)), 50.0, 50.0)?;
|
||||||
|
|
||||||
if state.ar2.is_none() {
|
if state.ar2.is_none() {
|
||||||
// inop alert
|
// inop alert
|
||||||
ctx.set_fill_style(&JsValue::from_str(TEXT_COLOR_RED));
|
ctx.set_fill_style(&JsValue::from_str(TEXT_COLOR_RED));
|
||||||
|
@ -62,6 +65,7 @@ pub fn render(state: &mut ScopeState) -> Result<(), JsValue> {
|
||||||
ctx.fill_text("NEW DATA AVAIL RLD RQD", 50.0, 50.0 + (state.prefs.fcs as f64) * 2.0)?;
|
ctx.fill_text("NEW DATA AVAIL RLD RQD", 50.0, 50.0 + (state.prefs.fcs as f64) * 2.0)?;
|
||||||
ctx.set_fill_style(&JsValue::from_str(TEXT_COLOR_GREEN));
|
ctx.set_fill_style(&JsValue::from_str(TEXT_COLOR_GREEN));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// render the command buffer
|
// render the command buffer
|
||||||
for (line_no, line) in state.command_buf.split('\n').enumerate() {
|
for (line_no, line) in state.command_buf.split('\n').enumerate() {
|
||||||
|
@ -69,6 +73,7 @@ pub fn render(state: &mut ScopeState) -> Result<(), JsValue> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// render the radar site info
|
// render the radar site info
|
||||||
|
if state.show_ui {
|
||||||
ctx.set_text_align("right");
|
ctx.set_text_align("right");
|
||||||
ctx.fill_text("RADAR SITE", (canvas.width() - 50) as f64, 50.0)?;
|
ctx.fill_text("RADAR SITE", (canvas.width() - 50) as f64, 50.0)?;
|
||||||
if let Some(ar2) = &state.ar2 {
|
if let Some(ar2) = &state.ar2 {
|
||||||
|
@ -78,7 +83,7 @@ pub fn render(state: &mut ScopeState) -> Result<(), JsValue> {
|
||||||
|
|
||||||
let seconds = delay.num_seconds() % 60;
|
let seconds = delay.num_seconds() % 60;
|
||||||
let minutes = (delay.num_seconds() / 60) % 60;
|
let minutes = (delay.num_seconds() / 60) % 60;
|
||||||
let hours = (delay.num_seconds() / 60) / 60;
|
let hours = delay.num_seconds() / 3600;
|
||||||
|
|
||||||
ctx.fill_text(&format!("SITE DELAY {:0>2}:{:0>2}:{:0>2}", hours, minutes, seconds), (canvas.width() - 50) as f64, 50.0 + (state.prefs.fcs as f64 * 2.0))?;
|
ctx.fill_text(&format!("SITE DELAY {:0>2}:{:0>2}:{:0>2}", hours, minutes, seconds), (canvas.width() - 50) as f64, 50.0 + (state.prefs.fcs as f64 * 2.0))?;
|
||||||
} else {
|
} else {
|
||||||
|
@ -105,7 +110,6 @@ pub fn render(state: &mut ScopeState) -> Result<(), JsValue> {
|
||||||
let x = (canvas.width() - 50) as f64;
|
let x = (canvas.width() - 50) as f64;
|
||||||
let y = (canvas.height() / 3) as f64 + (state.prefs.fcs * (line_no + 1)) as f64;
|
let y = (canvas.height() / 3) as f64 + (state.prefs.fcs * (line_no + 1)) as f64;
|
||||||
for (item_no, item) in line.iter().enumerate() {
|
for (item_no, item) in line.iter().enumerate() {
|
||||||
|
|
||||||
let pad_start = item_no;
|
let pad_start = item_no;
|
||||||
let pad_end = 2 - item_no;
|
let pad_end = 2 - item_no;
|
||||||
let pad_start = " ".repeat(pad_start * 6);
|
let pad_start = " ".repeat(pad_start * 6);
|
||||||
|
@ -140,26 +144,96 @@ pub fn render(state: &mut ScopeState) -> Result<(), JsValue> {
|
||||||
|
|
||||||
ctx.fill_text("ELEVATIONS", (canvas.width() - 50) as f64, ((canvas.height() / 7) * 4) as f64)?;
|
ctx.fill_text("ELEVATIONS", (canvas.width() - 50) as f64, ((canvas.height() / 7) * 4) as f64)?;
|
||||||
if let Some(ar2) = &state.ar2 {
|
if let Some(ar2) = &state.ar2 {
|
||||||
for (line_no, (elevation_no, scans)) in ar2.elevations.iter().sorted_by(|a, b| {
|
let mut line_no = 0;
|
||||||
|
|
||||||
|
for chunk in &ar2.elevations.iter().sorted_by(|a, b| {
|
||||||
Ord::cmp(&a.0, &b.0)
|
Ord::cmp(&a.0, &b.0)
|
||||||
}).enumerate() {
|
}).enumerate().chunks(4) {
|
||||||
|
for (no_in_line, (elevation_no, scans)) in chunk {
|
||||||
if state.selected_elevation != *elevation_no {
|
if state.selected_elevation != *elevation_no {
|
||||||
ctx.fill_text(&format!(" {:0>3} ", elevation_no), (canvas.width() - 50) as f64, ((canvas.height() / 7) * 4) as f64 + (state.prefs.fcs * (line_no + 1)) as f64)?;
|
ctx.fill_text(&format!(" {:0>3} {}", elevation_no, " ".repeat(5 * (3 - (no_in_line % 4)))), (canvas.width() - 50) as f64, ((canvas.height() / 7) * 4) as f64 + (state.prefs.fcs * (line_no + 1)) as f64)?;
|
||||||
} else {
|
} else {
|
||||||
ctx.set_fill_style(&JsValue::from_str(TEXT_COLOR_WHITE));
|
ctx.set_fill_style(&JsValue::from_str(TEXT_COLOR_WHITE));
|
||||||
ctx.fill_text(&format!(">{:0>3}<", elevation_no), (canvas.width() - 50) as f64, ((canvas.height() / 7) * 4) as f64 + (state.prefs.fcs * (line_no + 1)) as f64)?;
|
ctx.fill_text(&format!(">{:0>3}<{}", elevation_no, " ".repeat(5 * (3 - (no_in_line % 4)))), (canvas.width() - 50) as f64, ((canvas.height() / 7) * 4) as f64 + (state.prefs.fcs * (line_no + 1)) as f64)?;
|
||||||
ctx.set_fill_style(&JsValue::from_str(TEXT_COLOR_GREEN));
|
ctx.set_fill_style(&JsValue::from_str(TEXT_COLOR_GREEN));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
line_no += 1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ctx.fill_text("ELEVATION INFORMATION UNAVAILABLE", (canvas.width() - 50) as f64, ((canvas.height() / 7) * 4) as f64 + state.prefs.fcs as f64)?;
|
ctx.fill_text("ELEVATION INFORMATION UNAVAILABLE", (canvas.width() - 50) as f64, ((canvas.height() / 7) * 4) as f64 + state.prefs.fcs as f64)?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ACTUAL DATA RENDERING
|
// ACTUAL DATA RENDERING
|
||||||
if let Some(ar2) = &state.ar2 {
|
if let Some(ar2) = &state.ar2 {
|
||||||
let px_per_km = canvas.height() / RANGE as u32;
|
let px_per_km = (canvas.height() / RANGE as u32) as f32;
|
||||||
let xc = canvas.width() / 2;
|
let xc = canvas.width() / 2;
|
||||||
let yc = canvas.height() / 2;
|
let yc = canvas.height() / 2;
|
||||||
|
|
||||||
|
let radials = ar2.elevations.get(&state.selected_elevation).unwrap();
|
||||||
|
|
||||||
|
let first_gate_px = (radials[0].available_data.get("REF").expect("reflectivity is missing!").gdm.data_moment_range) as f32 / 1000.0 * px_per_km;
|
||||||
|
let gate_interval_km = (radials[0].available_data.get("REF").expect("reflectivity is missing!").gdm.data_moment_range_sample_interval) as f32 / 1000.0;
|
||||||
|
let gate_width_px = gate_interval_km * px_per_km;
|
||||||
|
|
||||||
|
for radial in radials {
|
||||||
|
/* weird rounding stolen from go-nexrad */
|
||||||
|
let mut azimuth_angle = (radial.header.azimuth_angle as f64) - 90.0;
|
||||||
|
if azimuth_angle < 0.0 {
|
||||||
|
azimuth_angle = 360.0 + azimuth_angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut azimuth = azimuth_angle.floor();
|
||||||
|
|
||||||
|
let azimuth_spacing = match radial.header.azimuth_resolution_spacing {
|
||||||
|
1 => 0.5,
|
||||||
|
_ => 1.0
|
||||||
|
};
|
||||||
|
if (azimuth_angle + azimuth_spacing).floor() > azimuth {
|
||||||
|
azimuth += azimuth_spacing;
|
||||||
|
}
|
||||||
|
/* conclude the weird rounding stolen from go-nexrad */
|
||||||
|
|
||||||
|
// Angles specified clockwise in radians
|
||||||
|
let start_angle = azimuth * (PI / 180.0);
|
||||||
|
let end_angle = azimuth_spacing * (PI / 180.0);
|
||||||
|
|
||||||
|
let mut distance_x = first_gate_px;
|
||||||
|
let mut distance_y = first_gate_px;
|
||||||
|
|
||||||
|
// line width
|
||||||
|
// line cap
|
||||||
|
|
||||||
|
let gates = radial.available_data.get(state.scope_mode.rname()).expect("selected unavailable product").scaled_data();
|
||||||
|
|
||||||
|
let num_gates = gates.len();
|
||||||
|
|
||||||
|
for (num, value) in gates.iter().enumerate() {
|
||||||
|
if *value != MOMENT_DATA_BELOW_THRESHOLD {
|
||||||
|
|
||||||
|
ctx.move_to(xc as f64 + start_angle.cos() * distance_x as f64, yc as f64 + start_angle.sin() * distance_y as f64);
|
||||||
|
|
||||||
|
ctx.begin_path();
|
||||||
|
|
||||||
|
if num == 0 {
|
||||||
|
ctx.ellipse(xc as f64, yc as f64, distance_x as f64, distance_y as f64, 0.0, start_angle - 0.001, end_angle + 0.001)?;
|
||||||
|
} else if num == num_gates - 1 {
|
||||||
|
ctx.ellipse(xc as f64, yc as f64, distance_x as f64, distance_y as f64, 0.0, start_angle, end_angle)?;
|
||||||
|
} else {
|
||||||
|
ctx.ellipse(xc as f64, yc as f64, distance_x as f64, distance_y as f64, 0.0, start_angle, end_angle + 0.001)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.set_stroke_style(&JsValue::from_str(&format!("{}px {}", gate_width_px + 1.0, color_scheme(state.scope_mode, *value))));
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
distance_x += gate_width_px;
|
||||||
|
distance_y += gate_width_px;
|
||||||
|
|
||||||
|
azimuth += azimuth_spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -13,7 +13,8 @@ pub struct ScopeState {
|
||||||
pub command_buf: String,
|
pub command_buf: String,
|
||||||
pub command_buf_response_mode: bool,
|
pub command_buf_response_mode: bool,
|
||||||
pub new_data_available: bool,
|
pub new_data_available: bool,
|
||||||
pub selected_elevation: usize
|
pub selected_elevation: usize,
|
||||||
|
pub show_ui: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RenderState {
|
pub struct RenderState {
|
||||||
|
|
|
@ -14,6 +14,8 @@ pub fn set_panic_hook() {
|
||||||
pub const MILLIS_PER_DAY: u128 = 86_400_000;
|
pub const MILLIS_PER_DAY: u128 = 86_400_000;
|
||||||
|
|
||||||
pub fn parse_date(julian: u32, millis: u32) -> DateTime<Utc> {
|
pub fn parse_date(julian: u32, millis: u32) -> DateTime<Utc> {
|
||||||
let unix_time_millis = (julian as u128) * MILLIS_PER_DAY + millis as u128;
|
let mut date = DateTime::UNIX_EPOCH;
|
||||||
DateTime::UNIX_EPOCH + Duration::milliseconds(unix_time_millis as i64)
|
date += Duration::days(julian as i64 - 1);
|
||||||
|
date += Duration::milliseconds(millis as i64);
|
||||||
|
date
|
||||||
}
|
}
|
|
@ -3,7 +3,8 @@ use std::fmt::{Debug, Formatter};
|
||||||
use std::io::{Cursor, Read};
|
use std::io::{Cursor, Read};
|
||||||
|
|
||||||
pub const MSG31_HEADER_LENGTH: usize = 4 + 4 + 2 + 2 + 4 + 1 + 1 + 2 + 1 + 1 + 1 + 1 + 4 + 1 + 1 + 2;
|
pub const MSG31_HEADER_LENGTH: usize = 4 + 4 + 2 + 2 + 4 + 1 + 1 + 2 + 1 + 1 + 1 + 1 + 4 + 1 + 1 + 2;
|
||||||
|
pub const MOMENT_DATA_BELOW_THRESHOLD: f32 = 999.0;
|
||||||
|
pub const MOMENT_DATA_FOLDED: f32 = 998.0;
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
#[cfg_attr(feature = "serde_derive", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde_derive", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct Message31Header {
|
pub struct Message31Header {
|
||||||
|
@ -138,10 +139,10 @@ impl DataMoment {
|
||||||
for gate in &gates {
|
for gate in &gates {
|
||||||
if *gate == 0 {
|
if *gate == 0 {
|
||||||
// below threshold
|
// below threshold
|
||||||
scaled_data.push(999.0);
|
scaled_data.push(MOMENT_DATA_BELOW_THRESHOLD);
|
||||||
} else if *gate == 1 {
|
} else if *gate == 1 {
|
||||||
// folded
|
// folded
|
||||||
scaled_data.push(998.0);
|
scaled_data.push(MOMENT_DATA_FOLDED);
|
||||||
} else {
|
} else {
|
||||||
scaled_data.push(scale_uint(*gate, self.gdm.offset, self.gdm.scale))
|
scaled_data.push(scale_uint(*gate, self.gdm.offset, self.gdm.scale))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue