some workings

This commit is contained in:
core 2023-11-04 00:08:31 -04:00
parent ced2b9be8b
commit 55936f0af4
Signed by: core
GPG Key ID: FDBF740DADDCEECF
10 changed files with 222 additions and 59 deletions

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/rtwx.iml" filepath="$PROJECT_DIR$/.idea/rtwx.iml" />
</modules>
</component>
</project>

14
.idea/rtwx.iml Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="EMPTY_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/nexrad-browser/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$/rtwx/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -0,0 +1,38 @@
# `CLF ...`
Currently loaded file.
| Command | Description | Example |
|-----------|-------------------------------------------------------------------------------------|-----------|
| `CLF OV` | Overwrite the currently loaded file with a new file from the file selection dialog. | `CLF OV` |
| `CLF LD` | Load the currently loaded file into the scope. | `CLF LD` |
| `CLF CLR` | Clear the currently loaded file. | `CLF CLR` |
# `POS ...`
Position.
| Command | Description | Example |
|----------------------------------|-------------------------------------------------------------|----------------------------|
| `POS SHOW` | Show the current position in latitude/longitude. | `POS SHOW` |
| `POS SLL [latitude] [longitude]` | Set the position to the desired latitude/longitude. | `POS SLL 38.8977 -77.0366` |
| `POS SITE [site]` | Set the position to the position of the desired radar site. | `POS SITE KRAX` |
# `PREF` and `PREFSET`
Preferences.
| Command | Description | Example |
|---------------------------|---------------------------------------------------|--------------------------------|
| `PREF SHOW [pref]` | Show the value of the preference. | `PREF SHOW RR` |
| `PREF SET [pref] [value]` | Set the value of the preference. | `PREF SET RR 5` |
| `PREF CLR [pref]` | Clear the prefernece (return to default value) | `PREF CLEAR RR` |
| `PREFSET SAVE [name]` | Save the current setup of the scope as a prefset. | `PREF SET SAVE krax_tornadoes` |
| `PREFSET RCL [name]` | Load the scope from the given prefset. | `PREF SET RCL krax_tornadoes` |
| `PREFSET CLR [name]` | Remove the saved prefset. | `PREF SET CLR krax_tornadoes` |
| `PREFSET CLRA` | Remove all saved prefsets. | `PREF SET CLRA` |
## Available Preferences
| Preference | Description | Value |
|------------|---------------------|----------------------------|
| RR | Range Rings | 1-100 (default 5) |
| RREN | Range Rings Enabled | true, false (default true) |
| FCS | Font Character Size | 1-100 (default 12) |

View File

View File

@ -2,36 +2,27 @@
<head> <head>
<title>NEXRAD Browser</title> <title>NEXRAD Browser</title>
<style> <style>
.grid-parent { @import url('https://fonts.googleapis.com/css2?family=VT323&display=swap');
display: grid;
grid-template-columns: 2fr .5fr; #canvas {
grid-template-rows: 1fr; width: 100%;
grid-column-gap: 5px;
grid-row-gap: 0px;
height: 100%; height: 100%;
image-rendering: pixelated;
} }
.canvas-container { body {
border-right: 2px solid black; margin: 0;
height: 100%; padding: 0;
} }
</style> </style>
</head> </head>
<body> <body>
<div class="grid-parent"> <canvas id="canvas">
<div class="canvas-container"> Something went wrong while loading the canvas. Sorry :/
<canvas id="canvas"></canvas> </canvas>
</div>
<div>
<label for="file">Upload Archive II file</label>
<input type="file" id="file" />
<button id="go">Load</button>
<hr>
</div>
</div>
<p style="font-family: 'vt323', monospace;">FONT TEST!</p>
<script src="bootstrap.js"></script> <script src="bootstrap.js"></script>
</body> </body>
</html> </html>

View File

@ -4,14 +4,69 @@ wasm.__nxrd_browser_init();
console.log("[JS] setup event listeners"); console.log("[JS] setup event listeners");
const fileSelector = document.getElementById('file'); console.log("[JS] initializing the renderer");
document.getElementById("go").addEventListener("click", (e) => {
const file = fileSelector.files[0];
const reader = new FileReader(); const DEFAULT_PREFERENCES = {
reader.addEventListener('load', (event) => { RR: 5,
let data = event.target.result; RREN: true,
wasm.load_ar2(data); FCS: 16
}); };
reader.readAsArrayBuffer(file); let preferences = DEFAULT_PREFERENCES;
});
function get_font_size() { return `${preferences.FCS}px `; }
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const FIFTY_MILES = 0.0916;
let current_lat = 38.8977;
let current_long = -77.036560;
function calcRenderbox() {
return [current_long - FIFTY_MILES, current_lat - FIFTY_MILES, current_long + FIFTY_MILES, current_lat + FIFTY_MILES];
}
function latlongXY(lat, long) {
let bbox = calcRenderbox();
let pixelWidth = canvas.width;
let pixelHeight = canvas.height;
let bboxWidth = bbox[2] - bbox[0];
let bboxHeight = bbox[3] - bbox[1];
let widthPct = ( long - bbox[0] ) / bboxWidth;
let heightPct = ( lat - bbox[1] ) / bboxHeight;
let x = Math.floor( pixelWidth * widthPct );
let y = Math.floor( pixelHeight * ( 1 - heightPct ) );
return { x, y };
}
let x0 = 0;
let y0 = 0;
let xfull = canvas.width;
let yfull = canvas.height;
function recalcBorderCoordinates() {
let xy = latlongXY(current_lat, current_long);
x0 = xy.x - canvas.width;
y0 = xy.y - canvas.height;
xfull = xy.x + (canvas.width / 2);
yfull = xy.y + (canvas.height / 2);
}
setInterval(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.font = get_font_size();
ctx.resetTransform();
recalcBorderCoordinates();
let xy = latlongXY(current_lat, current_long);
ctx.translate(xy.x, xy.y);
// background (black, always)
ctx.fillStyle = "black";
ctx.fillRect(x0, y0, xfull, yfull);
})

View File

@ -6,6 +6,13 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
#bzip2-rs = "0.1"
bzip2 = "0.4" bzip2-rs = { version = "0.1", optional = true }
bzip2 = { version = "0.4", optional = true }
log = "0.4" log = "0.4"
[features]
default = ["bzip-impl-bzip2-rs"]
bzip-impl-libbzip2 = ["bzip2"]
bzip-impl-bzip2-rs = ["bzip2-rs"]

26
nexrad2/src/bzip.rs Normal file
View File

@ -0,0 +1,26 @@
#[cfg(feature = "bzip-impl-libbzip2")]
pub mod _internal_ffi {
use bzip2::read::BzDecoder;
pub type BzipImpl<T> = BzDecoder<T>;
}
#[cfg(feature = "bzip-impl-bzip2-rs")]
pub mod _internal_pure {
use bzip2_rs::DecoderReader;
pub type BzipImpl<T> = DecoderReader<T>;
}
#[cfg(all(feature = "bzip-impl-bzip2-rs", feature = "bzip-impl-libbzip2"))]
compile_error!("Only one bzip2 implementation can be used. Please select bzip-impl-bzip2-rs or bzip-impl-libbzip2, but not both.");
#[cfg(not(any(feature = "bzip-impl-bzip2-rs", feature = "bzip-impl-libbzip2")))]
compile_error!("A bzip2 implementation is required. Please select either bzip-impl-bzip2-rs or bzip-impl-libbzip2.");
#[cfg(all(target_arch = "wasm32", feature = "bzip-impl-libbzip2"))]
compile_error!("bzip-impl-libbzip2 is not compatible with WebAssembly targets. Please use bzip-impl-bzip2-rs instead.");
#[cfg(feature = "bzip-impl-libbzip2")]
pub type BzipDecoder<T> = _internal_ffi::BzipImpl<T>;
#[cfg(feature = "bzip-impl-bzip2-rs")]
pub type BzipDecoder<T> = _internal_pure::BzipImpl<T>;

View File

@ -6,11 +6,12 @@ use std::fmt::{Display, Formatter};
use std::io; use std::io;
use std::io::{Cursor, Read, Seek, SeekFrom}; use std::io::{Cursor, Read, Seek, SeekFrom};
use std::str::Utf8Error; use std::str::Utf8Error;
use bzip2::read::BzDecoder;
//use bzip2_rs::DecoderReader;
use log::{debug, trace}; use log::{debug, trace};
use crate::bzip::BzipDecoder;
use crate::message::{LEGACY_CTM_HEADER_LEN, MESSAGE_BODY_SIZE, MESSAGE_HEADER_SIZE, MessageHeader};
pub mod message; pub mod message;
pub mod bzip;
#[derive(Debug)] #[derive(Debug)]
pub struct Nexrad2Chunk { pub struct Nexrad2Chunk {
@ -77,26 +78,6 @@ impl Error for NexradParseError {}
pub const NEXRAD2_META_CHUNK_FIXED_LENGTH: usize = 325888; pub const NEXRAD2_META_CHUNK_FIXED_LENGTH: usize = 325888;
pub const MESSAGE_HEADER_SIZE: usize = 2 + 1 + 1 + 2 + 2 + 4 + 2 + 2;
#[derive(Debug)]
pub struct MessageHeader {
pub message_size: u16,
pub rda_redundant_channel: u8,
pub message_type: u8,
pub message_sequence_number: u16,
pub julian_date: u16,
pub millis_after_midnight: u32,
pub num_of_message_segments: u16,
pub message_segment_num: u16
}
pub enum Message {
}
pub const LEGACY_TCM_HEADER_LENGTH: i64 = 12;
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];
@ -141,7 +122,7 @@ pub fn parse_nx2_chunk(cursor: &mut (impl Read + Seek)) -> Result<Nexrad2Chunk,
let mut compressed_buf = vec![0u8; ldm_size]; let mut compressed_buf = vec![0u8; ldm_size];
cursor.read_exact(&mut compressed_buf).map_err(|e| NexradParseError::LdmReadFailed(e))?; cursor.read_exact(&mut compressed_buf).map_err(|e| NexradParseError::LdmReadFailed(e))?;
let mut bz_decoder = BzDecoder::new(Cursor::new(compressed_buf)); let mut bz_decoder = BzipDecoder::new(Cursor::new(compressed_buf));
let mut decompressed_buf = vec![]; let mut decompressed_buf = vec![];
@ -151,11 +132,17 @@ pub fn parse_nx2_chunk(cursor: &mut (impl Read + Seek)) -> Result<Nexrad2Chunk,
let mut decompressed = Cursor::new(decompressed_buf); let mut decompressed = Cursor::new(decompressed_buf);
let mut messages = 0;
loop { loop {
decompressed.seek(SeekFrom::Current(LEGACY_TCM_HEADER_LENGTH)).map_err(|e| NexradParseError::TcmChunkReadFailed(e))?; decompressed.seek(SeekFrom::Current(LEGACY_CTM_HEADER_LEN as i64)).map_err(|e| NexradParseError::TcmChunkReadFailed(e))?;
let mut message_header = [0u8; MESSAGE_HEADER_SIZE]; let mut message_header = [0u8; MESSAGE_HEADER_SIZE];
decompressed.read_exact(&mut message_header).map_err(|e| NexradParseError::TcmChunkReadFailed(e))?; match decompressed.read_exact(&mut message_header) {
Ok(_) => (),
Err(e) if matches!(e.kind(), io::ErrorKind::UnexpectedEof) => { break; },
Err(e) => return Err(NexradParseError::TcmChunkReadFailed(e))
}
let message_header = MessageHeader { let message_header = MessageHeader {
message_size: u16::from_be_bytes(message_header[0..2].try_into().unwrap()), message_size: u16::from_be_bytes(message_header[0..2].try_into().unwrap()),
@ -170,9 +157,15 @@ pub fn parse_nx2_chunk(cursor: &mut (impl Read + Seek)) -> Result<Nexrad2Chunk,
debug!("Message: {:#?}", message_header); debug!("Message: {:#?}", message_header);
break; let mut body_buf = vec![0u8; MESSAGE_BODY_SIZE];
decompressed.read_exact(&mut body_buf).map_err(|e| NexradParseError::TcmChunkReadFailed(e))?;
messages += 1;
} }
debug!("{} messages loaded from chunk", messages);
break; break;
} }

View File

@ -1,3 +1,34 @@
pub const MSG_RDA_STATUS_DATA: u8 = 2;
pub const MSG_RDA_PERFORMANCE_DATA: u8 = 3;
pub const MSG_RDA_VOLUME_COVERAGE_DATA: u8 = 5;
pub const MSG_RDA_CLUTTER_FILTER_BYPASS_MAP: u8 = 13;
pub const MSG_RDA_CLUTTER_MAP_DATA: u8 = 15;
pub const MSG_RDA_ADAPTABLE_PARAMETERS: u8 = 18;
pub const MSG_MODEL_DATA_MESSAGE: u8 = 29;
pub const MSG_DIGITAL_RADAR_DATA_GENERIC: u8 = 31;
pub const LEGACY_CTM_HEADER_LEN: usize = 12;
pub const MESSAGE_HEADER_SIZE: usize = 16;
pub const DEFAULT_MESSAGE_SIZE: usize = 2432;
pub const MESSAGE_BODY_SIZE: usize = DEFAULT_MESSAGE_SIZE - LEGACY_CTM_HEADER_LEN - MESSAGE_HEADER_SIZE;
#[derive(Debug)]
pub struct MessageHeader {
pub message_size: u16,
pub rda_redundant_channel: u8,
pub message_type: u8,
pub message_sequence_number: u16,
pub julian_date: u16,
pub millis_after_midnight: u32,
pub num_of_message_segments: u16,
pub message_segment_num: u16
}
pub enum Message { pub enum Message {
/// Type02
RDAStatusData {
},
} }