rebuild factor

This commit is contained in:
Tsuki 2024-08-28 19:25:11 +08:00
parent ed9e8549aa
commit 6ceebdd7f4
24 changed files with 2983 additions and 274 deletions

20
Cargo.lock generated
View File

@ -732,7 +732,6 @@ dependencies = [
"iana-time-zone",
"js-sys",
"num-traits",
"serde",
"wasm-bindgen",
"windows-targets 0.52.6",
]
@ -1323,25 +1322,6 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "etws_loader"
version = "0.1.0"
dependencies = [
"abi_stable",
"anyhow",
"byteorder",
"chrono",
"flate2",
"geo 0.28.0",
"nom",
"nom-derive",
"num-traits",
"radarg_plugin_interface",
"serde",
"serde_json",
"thiserror",
]
[[package]]
name = "euclid"
version = "0.22.10"

View File

@ -1,7 +1,6 @@
[workspace]
members = [
"etws_loader",
"radarg_plugin_interface",
"geo-macros",
"radar-g",

View File

@ -1,188 +0,0 @@
mod error;
use geo::{algorithm::haversine_destination::HaversineDestination, Point};
mod parser;
use abi_stable::{
export_root_module,
prefix_type::PrefixTypeTrait,
sabi_extern_fn,
sabi_trait::prelude::TD_Opaque,
std_types::{
RNone, ROk,
ROption::RSome,
RResult::{self, RErr},
RStr, RString, RVec,
},
};
use parser::{Record, ValueResult};
use radarg_plugin_interface::{
DataLoaderPlugin, DataLoaderPlugin_TO, Error, GridDataInfo, LoadedData, PluginId, PluginMod,
PluginMod_Ref, PluginType, ProbeDataType, RadarGridData, VecResult,
};
macro_rules! data_rvec {
($data:ident, $({$parsed_vec:tt => $abi_stable_rvec:tt}),+) => {
match $data {
$(
ValueResult::$parsed_vec(data) => VecResult::$abi_stable_rvec(RVec::from(data)),
)+
}
};
}
macro_rules! data_type {
($datetype:ident, $({ $($name:literal)|+ => $type:tt }),+) => {
match $datetype {
$(
$($name)|+ => ProbeDataType::$type,
)+
_ => ProbeDataType::Unknown
}
};
}
#[export_root_module]
fn instantiate_root_module() -> PluginMod_Ref {
PluginMod { new }.leak_into_prefix()
}
struct ETWSLoader {
id: PluginId,
}
impl DataLoaderPlugin for ETWSLoader {
fn plugin_id(&self) -> &PluginId {
&self.id
}
fn load(&self, path: RStr<'_>) -> RResult<RVec<LoadedData>, Error> where {
if let Ok(record) = Record::parse_from_path(path.to_string()) {
let result = record
.blocks
.into_iter()
.map(|b| {
let data = b.data;
let converted_data = data_rvec!(
data,
{I16 => I16},
{F32 => F32},
{F64 => F64},
{I32 => I32},
{U32 => U32},
{I64 => I64},
{U64 => U64},
{I8 => I8},
{U8 => U8}
);
let dimension_values = convert_nested_vec_to_rvec(b.info.dimension_values);
let dimension_size = convert_vec_to_rvec(
b.info
.dimension_size
.into_iter()
.map(|p| p as usize)
.collect::<Vec<_>>(),
);
let dimension_names = convert_vec_to_rvec(
b.info
.dimension_des
.into_iter()
.map(RString::from)
.collect::<Vec<_>>(),
);
let fill_value = b.info.fill_value;
let value_name = RString::from(b.info.value_name);
let value_description = RString::from(b.info.value_des);
let datetime = record.filetime.timestamp();
let value_key = value_name.as_str();
let data_type = data_type!(
value_key,
{ "ET" => ET },
{ "DBZ" | "CR" | "FR" | "R" => DBZ},
{ "VIL" => VIL},
{ "EB" => EB},
{ "V" => V},
{ "ZDR" => ZDR},
{ "PHIDP" => PHIDP},
{ "KDP" => KDP},
{ "CC" =>CC},
{ "HCA" => HCA},
{ "QPE" => QPE},
{ "QPF" => QPF}
);
let grid_info = GridDataInfo {
shape: dimension_size,
dimensions: dimension_values,
dimension_names,
fill_value,
datetime: RSome(datetime),
value_description: RSome(value_description),
maybe_probe_data_type: RSome(data_type),
value_name,
dimension_description: "Wrong".into(),
};
LoadedData::RadarGridData(RadarGridData {
data: converted_data,
info: grid_info,
})
})
.collect::<RVec<_>>();
ROk(result)
} else {
RErr(Error::UnsupportedFormat)
}
}
fn plugin_info(&self) -> radarg_plugin_interface::PluginInfo where {
radarg_plugin_interface::PluginInfo {
plugin_type: "DataLoader".into(),
name: "ETWS_Loader".into(),
version: "0.1.0".into(),
author: "Tsuki".into(),
description: RSome("ETWS Loader".into()),
url: RSome("https://keitsuki.club".into()),
}
}
}
fn convert_iter_to_rvec<T>(raw: impl Iterator<Item = T>) -> RVec<T> {
RVec::from(raw.collect::<Vec<_>>())
}
fn convert_vec_to_rvec<T>(raw: Vec<T>) -> RVec<T> {
RVec::from(raw)
}
fn convert_nested_vec_to_rvec<T>(raw: Vec<Vec<T>>) -> RVec<RVec<T>> {
RVec::from(raw.into_iter().map(RVec::from).collect::<Vec<_>>())
}
#[sabi_extern_fn]
pub fn new(plugin_id: PluginId) -> RResult<PluginType, Error> {
let this = ETWSLoader { id: plugin_id };
ROk(DataLoaderPlugin_TO::from_value(this, TD_Opaque))
}
// 测试模块
#[cfg(test)]
mod tests {
// 导入外部作用域中的所有项
use super::*;
// 一个简单的测试
#[test]
fn test() {
let result =
Record::parse_from_path("/Volumes/data2/RadarArray/ShaoXing/radarData/OutputProducts/RadarProducts/BasicProductsX/20230627/20230627163400/ZJSXAA_20230627163400_VIL.dat.gz")
.unwrap();
}
}

View File

@ -61,13 +61,17 @@ impl App {
&mut self.context.programs
}
pub fn load_data(
&mut self,
data: &Vec<Data>,
setting: &radarg_core::config::Setting,
) -> Result<ModulePackage> {
self.program().load_data(data, setting)
pub fn supported_modules(&mut self) -> Vec<super::Modules> {
self.program().supported_modules()
}
// pub fn load_data(
// &mut self,
// data: &Vec<Data>,
// setting: &radarg_core::config::Setting,
// ) -> Result<ModulePackage> {
// self.program().load_data(data, setting)
// }
}
pub struct Context {

View File

@ -77,20 +77,20 @@ impl Programs {
PPIModule::new(&self.gl, &mut self._ppi, &mut self._text, &mut self._line)
}
pub fn load_data(
&mut self,
data: &Vec<Data>,
setting: &radarg_core::config::Setting,
) -> Result<ModulePackage> {
let data = &data[0];
match data {
Data::RadarGridData(ref grid_data) => {
self.ppi().load_data(grid_data, setting).map(|v| v.into())
}
_ => Err(Error::InvalidDataType),
}
pub fn supported_modules(&mut self) -> Vec<Modules> {
vec![Modules::PPI(self.ppi())]
}
// pub fn load_data(
// &mut self,
// data: &Vec<Data>,
// setting: &radarg_core::config::Setting,
// ) -> Result<Vec<ModulePackage>> {
// data.iter()
// .map(|d| self.ppi().load_data(, setting).map(|v| v.into()))
// .collect()
// }
pub fn draw_modules(
&mut self,
modules: &mut ModulePackage,
@ -108,7 +108,13 @@ impl Programs {
}
macro_rules! impl_module_package {
($({$t:ty => $b: tt | $c: ty}),+) => {
($({$t:ty => $b: tt | $module:tt | $c: ty}),+) => {
pub enum Modules<'b, 'gl: 'b>{
$(
$b($module<'b, 'gl>),
)+
}
#[derive(Debug)]
pub enum _ModulePackage {
@ -203,7 +209,7 @@ macro_rules! impl_module_package {
}
impl_module_package!(
{PPIPackage => PPI | PPIModuleConfigComponent}
{PPIPackage => PPI | PPIModule | PPIModuleConfigComponent}
);
impl ModulePackage {

View File

@ -438,8 +438,15 @@ impl SimpleComponent for PPIModuleConfigComponent {
let layer = this.value() as usize;
config_ref.borrow_mut().set_layer(layer);
}
},
gtk::Button {
set_label: "Refresh",
connect_clicked[sender] => move |_| {
sender.output(OutputMsg::Refresh);
}
}
}
}
fn init(

View File

@ -32,7 +32,7 @@ impl ColorMap {
float invalid = colormap_conf.w;
if (abs(value - invalid) < 0.0001) {
if (abs(value - invalid) < 0.0001 || value < vmin || value > vmax) {
return vec4(0.0, 0.0, 0.0, 0.0);
}

1383
loaders/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

2
loaders/Cargo.toml Normal file
View File

@ -0,0 +1,2 @@
[workspace]
members = ["etws_loader"]

View File

@ -7,6 +7,7 @@ edition = "2021"
[dependencies]
abi_stable = "*"
anyhow = "1.0.79"
bytemuck = "1.17.1"
byteorder = "1.5.0"
chrono = { version = "0.4.33", features = ["serde"] }
flate2 = "1.0.28"
@ -17,10 +18,11 @@ num-traits = "0.2.17"
serde = { version = "1.0.196", features = ["derive"] }
serde_json = "1.0.112"
thiserror = "1.0.56"
zip = "2.2.0"
[dependencies.radarg_plugin_interface]
version = "0.1"
path="../radarg_plugin_interface"
path = "../../radarg_plugin_interface"
[lib]
name = "etws_loader"

480
loaders/etws_loader/raw.py Normal file
View File

@ -0,0 +1,480 @@
"""
大探标准格式解析代码
"""
import gc
import numpy as np
import struct
__all__ = ['get_radar_data']
def get_radar_data_new(f):
"""
:param filename:
:return: dbz, vel, w, zdr, cc, dp, kdp, el_n, azm, el
"""
f.seek(0, 2)
block_length_all = f.tell()
f.seek(0)
GENERIC_HEADER = { # noqa
# 共32bit保留字节16bit
"Magic_Number": struct.unpack('I', f.read(4)), # 魔术字 - --固定标志,用来指示雷达数据文件
# "Major_Version": struct.unpack('h', f.read(2)), # 主版本号
# "Minor_Version": struct.unpack('h', f.read(2)), # 次版本号
"Major_Version": struct.unpack('H', f.read(2)), # 主版本号
"Minor_Version": struct.unpack('H', f.read(2)), # 次版本号
"Generic_Type": struct.unpack('I', f.read(4)),
# 文件类型 - --1基数据文件2气象产品文件3 - --体扫配置文件4 - --保留5 - --体扫调度配置文件6 - --雷达状态数据文件
"Product_Type": struct.unpack('I', f.read(4)), # 产品类型 - --仅在文件类型为2时生效
# 保留字节16bit
"Reserved": f.read(16)
}
# f.seek(32)
SITE_CONFIG = { # 共128bit保留字节46bit
"Site_Code": struct.unpack("8s", f.read(8))[0], # 站号 - --站号具有唯一性用来区别不同的雷达站如Z9010
"Site_Name": struct.unpack("32s", f.read(32))[0], # 站点名称 - --站点名称如BeiJing
"Latitude": struct.unpack('f', f.read(4))[0], # 纬度 - --雷达站天线所在位置纬度
"Longitude": struct.unpack('f', f.read(4))[0], # 经度 - --雷达站天线所在位置经度
"Antenna_Height": struct.unpack('I', f.read(4))[0], # 天线高度 - --天线馈源水平时海拔高度
"Ground_Height": struct.unpack('I', f.read(4)), # 地面高度 - --雷达塔楼地面海拔高度
"Frequency": struct.unpack('f', f.read(4)), # 工作频率
# TODO gyj modify
# "Beam_Width_Hori": struct.unpack('f', f.read(4)), # 水平波束宽度
# "Beam_Width_Vert": struct.unpack('f', f.read(4)), # 垂直波束宽度
"Antenna_Type": struct.unpack('I', f.read(4)), # 天线类型
"TR_Number": struct.unpack('I', f.read(4)), # 收发单元数量
"RDA_Version": struct.unpack('I', f.read(4)), # RDA版本号 - --雷达数据采集软件版本号
# TODO gyj modify
# 't':struct.unpack('h', f.read(2))[0],
"Radar_Type": {1: "SA", 2: "SB", 3: "SC", 4: "SAD", 7:'SPAR',8:'SPARD',
33: "CA", 34: "CB", 35: "CC", 36: "CCJ", 37: "CD", 38: "CAD",
43:'CPAR',44:'CPARD',
65: "XA", 66: "XAD",69:'XPAR',70:'XPARD'}.get(struct.unpack('h', f.read(2))[0]),
# 雷达类型 - --1SA2SB3SC4SAD33CA34CB35CC36CCJ37CD38CAD65XA66XAD
# 7SPAR 8SPARD 43CPAR 44CPARD 69XPAR 70XPARD
# "Antenna_Gain": struct.unpack('h', f.read(2)), # 天线增益 - --编码为实际100倍
# "Transmitting_feeder_loss": struct.unpack('h', f.read(2)), # 发射馈线损耗 - --编码为实际损耗100倍
# "Receiving_feeder_loss": struct.unpack('h', f.read(2)), # 接收馈线损耗 - --编码为实际损耗100倍
# "Other_Loss": struct.unpack('h', f.read(2)), # 其他损耗 - --编码为实际损耗100倍
# 保留字节46bit
"Reserved": f.read(54)
}
# f.seek(160)
TASK_CONFIG = { # 共256bit保留字节40bit
"Task_Name": struct.unpack("32s", f.read(32)), # 任务名称 - --任务名称如VCP21
"Task_Description": struct.unpack("128s", f.read(128)), # 任务描述
"Polarization_Type": struct.unpack('I', f.read(4))[0], # 极化方式 - --1 水平极化2 垂直极化3 水平 / 垂直同时4 水平 / 垂直交替
"Scan_Type": struct.unpack('I', f.read(4)
),
# 扫描任务类型 - --0 体扫1单层PPI2 单层RHI3 单层扇扫4 扇体扫5 多层RHI6 手工扫描
# "Pulse_Width": struct.unpack('I', f.read(4)
# ), # 脉冲宽度 - --发射脉冲宽度
# "Scan_Start_Time": struct.unpack('I', f.read(4)
# ), # 扫描开始时间 - --扫描开始时间为UTC标准时间计数, 1970年1月1日0时为起始计数基准点
#TODO gyj modify
'Scan_Beam_Number':struct.unpack('I', f.read(4)), #扫描配置中的发射波束数量
"Cut_Number": struct.unpack('I', f.read(4)
), # 扫描层数 - --根据扫描任务类型确定的扫描层数,与基数据保存的层数一致
"Ray_Order": struct.unpack('I', f.read(4)), #径向数据排序,0 按径向采集时间排序1 按先方位后俯仰方式排序
"Scan_Start_Time": struct.unpack('q', f.read(8)
), # 扫描开始时间 s - --扫描开始时间为UTC标准时间计数, 1970年1月1日0时为起始计数基准点
# "Horizontal_Noise": struct.unpack('f', f.read(4)
# ), # 水平通道噪声 - --水平通道的噪声电平
# "Vertical_Noise": struct.unpack('f', f.read(4)
# ), # 垂直通道噪声 - --垂直通道的噪声电平
# "Horizontal_Calibration": struct.unpack('f', f.read(4)
# ), # 水平通道标定值 - --水平通道的反射率标定常数
# "Vertical_Calibration": struct.unpack('f', f.read(4)
# ), # 水平通道噪声温度 - --垂直通道的反射率标定常数
# "Horizontal_Noise_Temperature": struct.unpack('f', f.read(4)
# ), # 水平通道噪声温度
# "Vertical_Noise_Temperature": struct.unpack('f', f.read(4)
# ), # 垂直通道噪声温度
# "ZDR_Calibration": struct.unpack('f', f.read(4)
# ), # ZDR标定偏差
# "PHIDP_Calibration": struct.unpack('f', f.read(4)
# ), # 差分相移标定偏差
# "LDR_Calibration": struct.unpack('f', f.read(4)
# ), # 系统LDR标定偏差
"Reserved": f.read(68)
# 保留字节68bit
}
# CUT_CONFIG = { # 每个仰角共256bit保留72bit
# }
# print(np.frombuffer(f.read(128),'S128')[0].decode('Windows-1252').encode("utf-8"))
cut_number = TASK_CONFIG.get("Cut_Number")[0] # 扫描层数
Scan_Beam_Number = TASK_CONFIG.get("Scan_Beam_Number")[0] #扫描配置中的发射波束数量
# print(cut_number)
SCAN_CONFIG = {}
for i in range(1, Scan_Beam_Number + 1):
# f.seek(416)
# 扫描波束配置块(一个)
SCAN_CONFIG[i] = {
'BEAM_INDEX': struct.unpack('I', f.read(4)), # 按扫描波束依次编号,一个体扫可由多个扫描波束组成,一个扫描波束可输出多个扫描仰角数据
'BEAM_TYPE': struct.unpack('I', f.read(4)), # 扫描波束类型 1 宽波束 2 窄波束
'SubPulse_Number': struct.unpack('I', f.read(4)), # 子脉冲数量,主工作脉冲和补盲子脉冲数量总和以下按作用距离由远及近排列14
'Tx_Beam_Direction': struct.unpack('f', f.read(4)), # 发射波束中心指向,发射波束中心的俯仰角指向-2.0090.00
'Tx_Beam_Width-H': struct.unpack('f', f.read(4)), # 发射波束水平宽度
'Tx_Beam_Width-V': struct.unpack('f', f.read(4)), # 发射波束垂直宽度
'Tx_Beam_Gain': struct.unpack('f', f.read(4)), # 发射波束中心增益
'Reserved': f.read(100) # 保留字节100bit
}
# cut_number = SCAN_CONFIG['0'].get("SubPulse_Number")[0]
# cut_number = 4
# print('cut_number: ',cut_number)
# 子脉冲参数块4个
for j in range(1, 5):
SCAN_CONFIG[i]['%d' % j] = { # 共128bit保留70bit
'SubPulse_Strategy': struct.unpack('I', f.read(4)), # 子脉冲策略 0=频分 1=时分
'SubPulse_Modulation': struct.unpack('I', f.read(4)), # 子脉冲调制方式 0=单载频 1=线性正调频ULFM 2=线性负调频DLFM 3=非线性正调频UNLFM 4=非线性负调频DNLFM
'SubPulse_Frequency': struct.unpack('f', f.read(4)), # 子脉冲频率,点频脉冲指工作频率,调频脉冲指中心频率, 1.00999,000.00
'SubPulse_BandWidth': struct.unpack('f', f.read(4)), # 子脉冲带宽,对调频模式有效,表示双边带宽, MHz兆赫 1.0099.00
'SubPulse_Width': struct.unpack('I', f.read(4)), # 子脉冲宽度,单位为纳秒ns,信号脉冲宽度(时长)
'Horizontal_Noise': struct.unpack('f', f.read(4)), # 水平通道噪声,dBm分贝毫瓦,水平通道的噪声电平-100.000.00
'Vertical_Noise': struct.unpack('f', f.read(4)), # 垂直通道噪声,dBm分贝毫瓦,垂直通道的噪声电平-100.000.00
'Horizontal_Calibration': struct.unpack('f', f.read(4)), # 水平通道标定偏差,dB分贝,水平通道的标定偏差0.00200.00
'Vertical_Calibration': struct.unpack('f', f.read(4)), # 垂直通道标定偏差,dB分贝,垂直通道的标定偏差0.00200.00
'Horizontal_Noise_Temperature': struct.unpack('f', f.read(4)), # 水平通道噪声温度,单位为K开氏温标,水平通道的噪声温度0.00800.00
'Vertical_Noise_Temperature': struct.unpack('f', f.read(4)), # 垂直通道噪声温度,单位为K开氏温标,垂直通道的噪声温度0.00800.00
'ZDR_Calibration': struct.unpack('f', f.read(4)), # ZDR标定偏差,dB分贝,水平通道的标定偏差 -10.0010.00
'PHIDP_Calibration': struct.unpack('f', f.read(4)), # PHIDP标定偏差,度,水平通道的标定偏差 -180.00180.00
'LDR_Calibration': struct.unpack('f', f.read(4)), # LDR标定偏差,dB分贝,水平通道的标定偏差 -600
'Pulse_Points': struct.unpack('h', f.read(2)), # 脉冲距离库数, 0~10000,该子脉冲探测的距离库数
'Reserved': f.read(70), # 保留字节70bit
}
# # # ========== 接收仰角配置块 ========
BEAM_CONFIG = {}
for i in range(1, cut_number + 1):
BEAM_CONFIG['%d' %i] = {
'Cut_Index': struct.unpack('h', f.read(2)), #扫描层索引, 1256, 基数据仰角编号
'Tx_Beam_Index': struct.unpack('h', f.read(2)), # 发射波束索引, 1256, 对应的发射波束索引
'Rx_Beam_Elevation': struct.unpack('f', f.read(4)), #接收波束指向,度, -2.0090.00, PPI模式的俯仰角
'Tx_Beam_Gain': struct.unpack('f', f.read(4)), #发射波束增益,,dB分贝, 在本接收方向上,发射波束的增益
'Rx_Beam_Width_H': struct.unpack('f', f.read(4)), #接收波束水平宽度, 度
'Rx_Beam_Width_V': struct.unpack('f', f.read(4)), #接收波束垂直宽度, 度
'Rx_Beam_Gain': struct.unpack('f', f.read(4)), #接收波束垂直宽度, dB分贝,
"Process_Mode": {1: "PPP", 2: "FFT"}.get(struct.unpack('I', f.read(4))[0]), # 处理模式---1---PPP2---FFT
"Wave_Form": {0: "CS连续监测", 1: "CD连续多普勒", 2: "CDX多普勒扩展", 3: "Rx Test", 4: "BATCH批模式", 5: "Dual PRF双PRF",
6: "Staggered PRT 参差PRT"}.get(struct.unpack('I', f.read(4))[0]),
# 波形类别---0 CS连续监测1 CD连续多普勒2 CDX多普勒扩展3 Rx Test4 BATC H批模式5 Dual PRF双PRF 6---Staggered PRT 参差PRT
"N1PRF1": struct.unpack('f', f.read(4)
), # 第一组脉冲重复频率1---单位赫兹Hz---对于Batch、双PRF和参差PRT模式表示高PRF值。对于其它单PRF模式表示唯一的PRF值。
"N1PRF2": struct.unpack('f', f.read(4)
), # 第一组脉冲重复频率2---单位赫兹Hz---对Batch、双PRF和参差PRT模式表示低PRF值。对其它单PRF模式无效。
"N2PRF1": struct.unpack('f', f.read(4)
), # 第二组脉冲重复频率1---单位赫兹Hz---对于Batch、双PRF和参差PRT模式表示高PRF值。对于其它单PRF模式表示唯一的PRF值。
"N2PRF2": struct.unpack('f', f.read(4)
), # 第二组脉冲重复频率2---单位赫兹Hz---对Batch、双PRF和参差PRT模式表示低PRF值。对其它单PRF模式无效。
"Dealiasing_Mode": struct.unpack('I', f.read(4)), # 速度退模糊方法---1 单PRF2 双PRF3:2模式3 双PRF4:3模式4 双PRF 5:4模式
"Azimuth": struct.unpack('f', f.read(4)), # 方位角---RHI模式的方位角, 度0.00360.00, PPI模式的俯仰角同参数接收波
# "Elevation": struct.unpack('f', f.read(4)), # 俯仰角---PPI模式的俯仰角
"Start_Angle": struct.unpack('f', f.read(4)), # 起始角度----度,-10.00360.00---PPI扇扫的起始方位角或RHI模式的高限仰角
"End_Angle": struct.unpack('f', f.read(4)), # 结束角度---度,-10.00360.00---PPI扇扫的结束方位角或RHI模式的低限仰角
"Angular_Resolution": struct.unpack('f', f.read(4)), # 角度分辨率--度,---径向数据的角度分辨率仅用于PPI扫描模式
"Scan_Speed": struct.unpack('f', f.read(4)), # 扫描速度---度/秒---0.00100.00---PPI扫描的方位转速或RHI扫描的俯仰转速
"Log_Resolution": struct.unpack('f', f.read(4)), # 强度分辨率---米---15,000---强度数据的距离分辨率,支持浮点分辨率
"Doppler_Resolution": struct.unpack('f', f.read(4)), # 多普勒分辨率---米---15,000---多普勒数据的距离分辨率
"Maximum_Range1": struct.unpack('I', f.read(4)), # 最大距离1---米---1500,000---对应脉冲重复频率1的最大可探测距离
"Maximum_Range2": struct.unpack('I', f.read(4)), # 最大距离2---米---1500,000---对应脉冲重复频率2的最大可探测距离
"Start_Range": struct.unpack('I', f.read(4)), # 起始距离---米---1500,000---数据探测起始距离
"Sample1": struct.unpack('I', f.read(4)), # 采样个数1---2512---对应于脉冲重复频率1的采样个数
"Sample2": struct.unpack('I', f.read(4)), # 采样个数2---2512---对应于脉冲重复频率2的采样个数
"Phase_Mode": struct.unpack('I', f.read(4)), # 相位编码模式---1 固定相位;2 随机相位;3 SZ编码
"Atmospheric_Loss": struct.unpack('f', f.read(4)), # 大气衰减---分贝/千米--0.00000010.000000---双程大气衰减值精度为小数点后保留6位
"Nyquist_Speed": struct.unpack('f', f.read(4)), # 最大不模糊速度---米/秒---0100---理论最大不模糊速度
"Moments_Mask": struct.unpack("q", f.read(8)), # 数据类型掩码---00xFFFFFFFFFFFFFFFF---以掩码的形式表示当前允许获取的数据类型其中0不允许获取数据;1 –允许获取数据。(json1)
"Moments_Size_Mask": struct.unpack("q", f.read(8)),# 数据大小掩码---00xFFFFFFFFFFFFFFFF---以掩码形式表示每种数据类型字节数其中01个字节;1 2个字节(json1)
"Misc_Filter_Mask": struct.unpack('I', f.read(4)), # 滤波设置掩码--00xFFFFFFFF---0未应用;1应用(json2)
"SQI_Threshold": struct.unpack('f', f.read(4)), # SQI门限---0.001.00----
"SIG_Threshold": struct.unpack('f', f.read(4)), # SIG门限--dB分贝---0.0020.00
"CSR_Threshold": struct.unpack('f', f.read(4)), # CSR门限--dB分贝--0.00100.00
"LOG_Threshold": struct.unpack('f', f.read(4)), # LOG门限--dB分贝--0.0020.00
"CPA_Threshold": struct.unpack('f', f.read(4)), # CPA门限--0.00100.00--
"PMI_Threshold": struct.unpack('f', f.read(4)), # PMI门限--0.001.00
"DPLOG_Threshold": struct.unpack('f', f.read(4)), # DPLOG门限--0.00100.00
"Thresholds_r": struct.unpack('4s', f.read(4)), #阈值门限保留---水平通道的反射率标定常数 =======保留字段======
# 这个时保留字段 "Thresholds_r":data.slice(548,552),#阈值门限保留---水平通道的反射率标定常数
"dBT_Mask": struct.unpack('I', f.read(4)), # dBT质控掩码---00xFFFFFFFF---dBT数据使用的质控门限掩码其中0未应用,1应用(json3)
"dBZ_Mask": struct.unpack('I', f.read(4)), # dBZ质控掩码---dBZ数据使用的质控门限掩码, 其中0未应用,1应用(json3)
"Velocity_Mask": struct.unpack('I', f.read(4)), # 速度质控掩码----00xFFFFFFFF---速度数据使用的质控门限掩码, 其中0未应用,1应用(json3)
"Spectrum_Width_Mask": struct.unpack('I', f.read(4)), # 谱宽质控掩码----00xFFFFFFFF--谱宽数据使用的质控门限掩码,其中0未应用,1应用(json3)
"DP_Mask": struct.unpack('I', f.read(4)), # 偏振量质控掩码----00xFFFFFFFF--偏振量数据使用的质控门限掩码,其中0未应用,1应用(json3)
"Mask_Reserved": f.read(12), # 保留字节12bit
'Reserved': f.read(4), # 保留字节4bit
# 保留12bit
# "Scan_Sync": struct.unpack('I', f.read(4)), # 扫描同步标志---用于多部雷达同步扫描标识
"Direction": struct.unpack('I', f.read(4)), # 天线运行方向---仅对PPI模式有效1 顺时针;2 逆时针
"Ground_Clutter_Classifier_Type": struct.unpack('h', f.read(2)), # 地物杂波图类型---1 所有数据不滤波;2 全程滤波;3 使用实时动态滤波图;4 使用静态滤波图
"Ground_Clutter_Filter_Type": struct.unpack('h', f.read(2)),
# 地物滤波类型---0 –不滤波;1 频域自适应滤波;2 - 固定宽带频域滤波器;3 - 可变宽带频域滤波器;4 - 可变最小方差频域滤波器;5 IIR时域滤波
"Ground_Clutter_Filter_Notch_Width": struct.unpack('h', f.read(2)), # 地物滤波宽度--0.1 米/秒--0.110.0
"Ground_Clutter_Filter_Window": struct.unpack('h', f.read(2)),
# 滤波窗口类型---滤波算法FFT窗口类型;0 矩形窗;1 汉明窗;2 Blackman窗;3 自适应窗口;4
"Reserved": f.read(44), # 保留字节44bit
}
#TODO
# radar_range = np.arange(BEAM_CONFIG['1']['Sample1'][0]) * BEAM_CONFIG['1']['Log_Resolution'][0]
data_block = f.tell()
# print(data_block)
# return
data_shape = {}
# for J in range(radial_number):
RadialData = {
# 径向头共128字节 保留13 字节
"Radial_State": struct.unpack('I', f.read(4)),
# 径向数据状态 - --0仰角开始1中间数据2仰角结束3体扫开始4体扫结束5RHI开始6RHI结束
"Spot_Blank": struct.unpack('I', f.read(4)), # 消隐标志 - --0正常1消隐
"Sequence_Number": struct.unpack('I', f.read(4)), # 序号 - 165536--每个体扫径向从1计数
"Radial_Number": struct.unpack('I', f.read(4)), # 径向数 - 11000--每个扫描从1计数
"Elevation_Number": struct.unpack('I', f.read(4)), # 仰角编号 - --仰角编号每个体扫从1计数
"Azimuth": struct.unpack('f', f.read(4)), # 方位角 ---度 0.00360.00 --扫描的方位角度
"Elevation": struct.unpack('f', f.read(4)), # 仰角 ---度 -2.0090.00--扫描的俯仰角度
"Seconds": struct.unpack('q', f.read(8)), # 秒 - --径向数据采集的时间UTC计数的秒数, 从1970年1月1日0时开始计数
"Microseconds": struct.unpack('I', f.read(4)), # 微秒 - --径向数据采集的时间除去UTC秒数后留下的微秒数
"Length_of_data": struct.unpack('I', f.read(4)), # 数据长度 --1100000 --仅本径向数据块所占用的长度如有压缩,长度为压缩后数据长度
"Moment_Number": struct.unpack('I', f.read(4)), # 数据类别数量 ---164 --径向数据类别如ZVW等各占一种的数量
"Scan Beam Index": struct.unpack('h', f.read(2)), # 波束编号 ---1-32 --波束编号
"Horizontal_Estimated_Noise": struct.unpack('h', f.read(2)), # 径向的水平估计噪声 --dB分贝 --编码为实际噪声的 - 100倍
"Vertical_Estimated_Noise": struct.unpack('h', f.read(2)), # 径向的垂直估计噪 - --编码为实际噪声的 - 100 倍
"PRF_FLAG": struct.unpack('I', f.read(4)), #重频标志, 11 N1 PRF #1 ; 12 N1 PRF #2; 21 N2 PRF #1; 22 N2 PRF #2; 排列方式11128888表示使用N1 PRF #1和PRF #2 #######################uint
# 88882122表示使用N2 PRF #1和PRF #2 11122122表示使用N1和N2的PRF #1和PRF #2 对应表2-7中09-13的描述8表示无效填充数据弥补用0表示会出现的问题
# "Zip_Type": struct.unpack('h', f.read(2)), # 压缩类型 - --0 - 不压缩1 - LZO压缩
"Reversed": f.read(70) # 保留70bit
}
radial_number = RadialData.get("Radial_Number")[0] # 径向数 J
type_number = RadialData.get("Moment_Number")[0] # 数据类别数量 K
typeHeader = {}
# for J in range(radial_number):
# for K in range(type_number):
for i in range(type_number):
# typeHeader[J][K] = {
typeHeader = {
# 共32字节
"Data_Type": struct.unpack('I', f.read(4)), # 数据类型 ---164 --具体径向数据类型见表2 - 6
"Scale": struct.unpack('I', f.read(4)), # 比例 --032768 --数据编码的比例
"Offset": struct.unpack('I', f.read(4)), # 偏移 --032768 --数据编码的偏移
"Bin_Length": struct.unpack('h', f.read(2)), # 库字节长度 - --保存一个距离库值用的字节数
"Flags": struct.unpack('h', f.read(2)), # 标志 - --数据标志位,暂不使用
"Length": struct.unpack('I', f.read(4)), # 长度 --132768 --距离库数据的长度,不包括当前的径向数据头大小
"Reserved": f.read(12)
}
block_length = typeHeader.get("Length")[0]
bin_length = typeHeader.get("Bin_Length")[0]
offset = typeHeader.get("Offset")[0]
scale = typeHeader.get("Scale")[0]
data_body = f.read(block_length)
raw = np.frombuffer(data_body, 'u' + str(bin_length)).astype(np.float64)
#TODO
if i ==0:
radar_range = np.arange(len(raw))*30
raw[raw <= 5.] = np.nan
# 对于保存的编码值来说5以下的值表示特殊意义不应该被解码。
value = (raw - offset) / scale
data_type = typeHeader.get("Data_Type")[0]
data_shape[data_type] = value.shape[0]
block_index = f.tell()
roll_num = int((block_length_all - data_block) / (block_index - data_block))
azm_num = int(roll_num / cut_number)
gc.collect()
# print("=========",data_shape)
# return get_radial_data(f, cut_number, azm_num, data_shape, data_block, SITE_CONFIG, radar_range, TASK_CONFIG['Polarization_Type'])
return get_radial_data(f, cut_number, azm_num, data_shape, data_block, SITE_CONFIG, radar_range, TASK_CONFIG['Polarization_Type'], BEAM_CONFIG)
def get_radial_data(f, cut_number, azm_num, data_shape, data_block, site_config, radar_range, polar_type, BEAM_CONFIG):
"""
:param f:
:param cut_number: cut number
:param azm_num: number of azm
:param data_shape: length of block
:return: dbz, vel, w, zdr, cc, dp, kdp, el_n, azm, el
dbz:滤波后反射率(Reflectivity) dBZ
vel:径向速度(Doppler Velocity) V
w:谱宽Spectrum Width W
zdr_:差分反射率Differential Reflectivity ZDR
cc_:协相关系数Cross Correlation Coefficient CC
dp_:差分相移Differential Phase DP
kdp_差分相移率Specific Differential Phase KDp
azm:方位角 维度1
el:仰角 维度 1
"""
_data_dict = {}
for k, v in data_shape.items():
if k == 2:
dbz = np.empty((cut_number, azm_num, v), dtype=np.float64)
_data_dict['reflectData'] = dbz
elif k == 3:
vel = np.empty((cut_number, azm_num, v), dtype=np.float64)
_data_dict['velData'] = vel
elif k == 4:
w = np.empty((cut_number, azm_num, v), dtype=np.float64)
_data_dict['widData'] = w
elif k == 7:
zdr = np.empty((cut_number, azm_num, v), dtype=np.float64)
_data_dict['zdrData'] = zdr
elif k == 9:
cc = np.empty((cut_number, azm_num, v), dtype=np.float64)
_data_dict['ccData'] = cc
elif k == 10:
dp = np.empty((cut_number, azm_num, v), dtype=np.float64)
_data_dict['dpData'] = dp
elif k == 11:
kdp = np.empty((cut_number, azm_num, v), dtype=np.float64)
_data_dict['kdpData'] = kdp
el_n = np.empty((cut_number, azm_num), np.int32)
azm = np.empty((cut_number, azm_num), np.float32)
el = np.empty((cut_number, azm_num), np.float32)
f.seek(data_block)
for j in range(cut_number):
for k in range(azm_num):
RadialData = {
# 共64字节 保留13 字节
"Radial_State": struct.unpack('I', f.read(4)),
# 径向数据状态 - --0仰角开始1中间数据2仰角结束3体扫开始4体扫结束5RHI开始6RHI结束
"Spot_Blank": struct.unpack('I', f.read(4)
), # 消隐标志 - --0正常1消隐
"Sequence_Number": struct.unpack('I', f.read(4)
), # 序号 - --每个体扫径向从1计数
"Radial_Number": struct.unpack('I', f.read(4)
), # 径向数 - --每个扫描从1计数
"Elevation_Number": struct.unpack('I', f.read(4)
), # 仰角编号 - --仰角编号每个体扫从1计数
"Azimuth": struct.unpack('f', f.read(4)
), # 方位角 - --扫描的方位角度
"Elevation": struct.unpack('f', f.read(4)
), # 仰角 - --扫描的俯仰角度
"Seconds": struct.unpack('q', f.read(8)
), # 秒 - --径向数据采集的时间UTC计数的秒数, 从1970年1月1日0时开始计数
"Microseconds": struct.unpack('I', f.read(4)
), # 微秒 - --径向数据采集的时间除去UTC秒数后留下的微秒数
"Length_of_data": struct.unpack('I', f.read(4)
), # 数据长度 - --仅本径向数据块所占用的长度如有压缩,长度为压缩后数据长度
"Moment_Number": struct.unpack('I', f.read(4)
), # 数据类别数量 - --径向数据类别如ZVW等各占一种的数量
"Scan Beam Index": struct.unpack('h', f.read(2)
), # 波束编号 ---1-32 --波束编号
"Horizontal_Estimated_Noise": struct.unpack('h', f.read(2)
), # 径向的水平估计噪声 - --编码为实际噪声的 - 100倍
"Vertical_Estimated_Noise": struct.unpack('h', f.read(2)
), # 径向的垂直估计噪 - --编码为实际噪声的 - 100 倍
"PRF_FLAG": struct.unpack('I', f.read(4)), #重频标志, 11 N1 PRF #1 ; 12 N1 PRF #2; 21 N2 PRF #1; 22 N2 PRF #2; 排列方式11128888表示使用N1 PRF #1和PRF #2 #######################uint
# 88882122表示使用N2 PRF #1和PRF #2 11122122表示使用N1和N2的PRF #1和PRF #2 对应表2-7中09-13的描述8表示无效填充数据弥补用0表示会出现的问题
# "Zip_Type": struct.unpack('h', f.read(2)
# ), # 压缩类型 - --0 - 不压缩1 - LZO压缩
"Reversed": f.read(70) # 保留13bit
}
# print(f.tell())
# f.seek(8672)
el_n_ = RadialData.get("Elevation_Number")[0]
azm_ = RadialData.get("Azimuth")[0]
# el_ = RadialData.get("Elevation")[0]
el_ = BEAM_CONFIG['%d' %(j+1)]["Rx_Beam_Elevation"][0]
type_number = RadialData.get("Moment_Number")[0]
for i in range(type_number):
typeHeader = {
# 共32字节
"Data_Type": struct.unpack('I', f.read(4)), # 数据类型 - --具体径向数据类型见表2 - 6
"Scale": struct.unpack('I', f.read(4)
), # 比例 - --数据编码的比例
"Offset": struct.unpack('I', f.read(4)
), # 偏移 - --数据编码的偏移
"Bin_Length": struct.unpack('h', f.read(2)
), # 库字节长度 - --保存一个距离库值用的字节数
"Flags": struct.unpack('h', f.read(2)
), # 标志 - --数据标志位,暂不使用
"Length": struct.unpack('I', f.read(4)
), # 长度 - --距离库数据的长度,不包括当前的径向数据头大小
"Reserved": f.read(12)
}
# print(typeHeader)
data_type = typeHeader.get("Data_Type")[0]
scale = typeHeader.get("Scale")[0]
offset = typeHeader.get("Offset")[0]
bin_length = typeHeader.get("Bin_Length")[0]
block_length = typeHeader.get("Length")[0]
data_body = f.read(block_length)
dtype = "u%d" % bin_length
# print(body)
raw = np.frombuffer(data_body, dtype).astype(np.float64)
# raw = np.asarray(struct.unpack(str(block_length) + "B", data_body)).astype(np.float64)
raw[raw <= 5.] = np.nan
value = (raw - offset) / scale
# print(np.nanmin(value))
# print(np.nanmax(value))
if data_type == 2:
# dbz[el_n_ - 1, k, :] = value
dbz[el_n_ - 1, k, :len(value)] = value
elif data_type == 3:
# vel[el_n_ - 1, k, :] = value
vel[el_n_ - 1, k, :len(value)] = value
elif data_type == 4:
# w[el_n_ - 1, k, :] = value
w[el_n_ - 1, k, :len(value)] = value
elif data_type == 7:
# zdr[el_n_ - 1, k, :] = value
zdr[el_n_ - 1, k, :len(value)] = value
elif data_type == 9:
# cc[el_n_ - 1, k, :] = value
cc[el_n_ - 1, k, :len(value)] = value
elif data_type == 10:
# dp[el_n_ - 1, k, :] = value
dp[el_n_ - 1, k, :len(value)] = value
elif data_type == 11:
# kdp[el_n_ - 1, k, :] = value
kdp[el_n_ - 1, k, :len(value)] = value
el_n[el_n_ - 1, k] = el_n_
azm[el_n_ - 1, k] = azm_
el[el_n_ - 1, k] = el_
# print(f"the No.{el_n_} elevation is {el_}")
gc.collect()
result = {
'radarNumber': site_config['Site_Code'],
'longitude': site_config['Longitude'],
'latitude': site_config['Latitude'],
'altitude': site_config['Antenna_Height'],
'radarRange': radar_range,
'azimuthData': azm[1, :],
'elevationData': el[:, 1],
'polar_type': polar_type
}
result.update(_data_dict)
f.close()
return result

View File

@ -0,0 +1,252 @@
mod error;
mod raw;
use raw::parse_raw_data;
mod parser;
use abi_stable::{
export_root_module,
prefix_type::PrefixTypeTrait,
rvec, sabi_extern_fn,
sabi_trait::prelude::TD_Opaque,
std_types::{
RNone, ROk,
ROption::RSome,
RResult::{self, RErr},
RStr, RString, RVec,
},
};
use parser::{Record, ValueResult};
use radarg_plugin_interface::{
DataLoaderPlugin, DataLoaderPlugin_TO, Error, GridDataInfo, LoadedData, PluginId, PluginMod,
PluginMod_Ref, PluginType, ProbeDataType, RadarGridData, VecResult,
};
macro_rules! data_rvec {
($data:ident, $({$parsed_vec:tt => $abi_stable_rvec:tt}),+) => {
match $data {
$(
ValueResult::$parsed_vec(data) => VecResult::$abi_stable_rvec(RVec::from(data)),
)+
}
};
}
macro_rules! data_type {
($datetype:ident, $({ $($name:literal)|+ => $type:tt }),+) => {
match $datetype {
$(
$($name)|+ => ProbeDataType::$type,
)+
_ => ProbeDataType::Unknown
}
};
}
#[export_root_module]
fn instantiate_root_module() -> PluginMod_Ref {
PluginMod { new }.leak_into_prefix()
}
struct ETWSLoader {
id: PluginId,
}
impl DataLoaderPlugin for ETWSLoader {
fn plugin_id(&self) -> &PluginId {
&self.id
}
fn load(&self, path: RStr<'_>) -> RResult<RVec<LoadedData>, Error> where {
let path = path.as_str();
let c = Record::parse_from_path(path.to_string())
.map(|record| {
let result = record
.blocks
.into_iter()
.map(|b| {
let data = b.data;
let converted_data = data_rvec!(
data,
{I16 => I16},
{F32 => F32},
{F64 => F64},
{I32 => I32},
{U32 => U32},
{I64 => I64},
{U64 => U64},
{I8 => I8},
{U8 => U8}
);
let dimension_values = convert_nested_vec_to_rvec(b.info.dimension_values);
let dimension_size = convert_vec_to_rvec(
b.info
.dimension_size
.into_iter()
.map(|p| p as usize)
.collect::<Vec<_>>(),
);
let dimension_names = convert_vec_to_rvec(
b.info
.dimension_des
.into_iter()
.map(RString::from)
.collect::<Vec<_>>(),
);
let fill_value = b.info.fill_value;
let value_name = RString::from(b.info.value_name);
let value_description = RString::from(b.info.value_des);
let datetime = record.filetime.timestamp();
let value_key = value_name.as_str();
let data_type = data_type!(
value_key,
{ "ET" => ET },
{ "DBZ" | "CR" | "FR" | "R" => DBZ},
{ "VIL" => VIL},
{ "EB" => EB},
{ "V" => V},
{ "ZDR" => ZDR},
{ "PHIDP" => PHIDP},
{ "KDP" => KDP},
{ "CC" =>CC},
{ "HCA" => HCA},
{ "QPE" => QPE},
{ "QPF" => QPF}
);
let grid_info = GridDataInfo {
shape: dimension_size,
dimensions: dimension_values,
dimension_names,
fill_value,
datetime: RSome(datetime),
value_description: RSome(value_description),
maybe_probe_data_type: RSome(data_type),
value_name,
dimension_description: "Wrong".into(),
};
LoadedData::RadarGridData(RadarGridData {
data: converted_data,
info: grid_info,
})
})
.collect::<RVec<_>>();
result
})
.or_else(|_| {
let result = parse_raw_data(path)
.map(|result| {
let data = result.datas;
let shape = rvec![
result.els.len() as usize,
result.azs.len() as usize,
result.ranges.len() as usize
];
let dimensions = rvec![
RVec::from(result.els),
RVec::from(result.azs),
RVec::from(result.ranges)
];
let dimension_names = rvec!["el".into(), "az".into(), "range".into()];
let datetime = result.datetime;
let loaded = data
.into_iter()
.map(move |(k, v)| {
let data_type = data_type!(
k,
{ "ET" => ET },
{ "DBZ" | "CR" | "FR" | "R" => DBZ},
{ "VIL" => VIL},
{ "EB" => EB},
{ "V" => V},
{ "ZDR" => ZDR},
{ "PHIDP" => PHIDP},
{ "KDP" => KDP},
{ "CC" =>CC},
{ "HCA" => HCA},
{ "QPE" => QPE},
{ "QPF" => QPF}
);
let radar_data = RadarGridData {
data: VecResult::F64(RVec::from(v)),
info: GridDataInfo {
shape: shape.clone(),
dimensions: dimensions.clone(),
dimension_names: dimension_names.clone(),
fill_value: 0.0,
datetime: RSome(datetime),
value_description: RNone,
maybe_probe_data_type: RSome(data_type),
value_name: RString::from(k),
dimension_description: "Wrong".into(),
},
};
LoadedData::RadarGridData(radar_data)
})
.collect::<RVec<_>>();
loaded
})
.map_err(|_| Error::UnsupportedFormat)?;
Ok(result)
});
RResult::from(c)
}
fn plugin_info(&self) -> radarg_plugin_interface::PluginInfo where {
radarg_plugin_interface::PluginInfo {
plugin_type: "DataLoader".into(),
name: "ETWS_Loader".into(),
version: "0.1.0".into(),
author: "Tsuki".into(),
description: RSome("ETWS Loader".into()),
url: RSome("https://keitsuki.club".into()),
}
}
}
fn convert_iter_to_rvec<T>(raw: impl Iterator<Item = T>) -> RVec<T> {
RVec::from(raw.collect::<Vec<_>>())
}
fn convert_vec_to_rvec<T>(raw: Vec<T>) -> RVec<T> {
RVec::from(raw)
}
fn convert_nested_vec_to_rvec<T>(raw: Vec<Vec<T>>) -> RVec<RVec<T>> {
RVec::from(raw.into_iter().map(RVec::from).collect::<Vec<_>>())
}
#[sabi_extern_fn]
pub fn new(plugin_id: PluginId) -> RResult<PluginType, Error> {
let this = ETWSLoader { id: plugin_id };
ROk(DataLoaderPlugin_TO::from_value(this, TD_Opaque))
}
// 测试模块
#[cfg(test)]
mod tests {
// 导入外部作用域中的所有项
use super::*;
// 一个简单的测试
#[test]
fn test() {
let result =
Record::parse_from_path("/Volumes/data2/RadarArray/ShaoXing/radarData/OutputProducts/RadarProducts/BasicProductsX/20230627/20230627163400/ZJSXAA_20230627163400_VIL.dat.gz")
.unwrap();
}
}

View File

@ -10,7 +10,7 @@ use nom::{
use nom_derive::*;
use serde::{Deserialize, Serialize};
use std::fs::File;
use std::io::{self, Read, Write};
use std::io::Read;
use std::path::Path;
pub enum ValueResult {

View File

@ -0,0 +1,753 @@
use abi_stable::std_types::vec;
use bytemuck::cast_slice;
use nom::{
bytes::complete::take,
combinator::map,
number::complete::{le_f32, le_i16, le_i64, le_u16, le_u32},
sequence::tuple,
IResult,
};
use zip::read::ZipArchive;
use std::{
collections::HashMap,
io::{self, Cursor, Read, Seek, SeekFrom},
process::id,
};
use std::{fs::File, path::Path};
const SUPPORTED_TYPE: [u32; 7] = [2, 3, 4, 7, 9, 10, 11];
#[derive(Debug)]
pub struct RadarData {
pub datetime: i64,
pub els: Vec<f64>,
pub azs: Vec<f64>,
pub ranges: Vec<f64>,
pub datas: HashMap<&'static str, Vec<f64>>,
}
#[derive(Debug)]
struct SiteConfig {
site_code: String,
site_name: String,
latitude: f32,
longitude: f32,
antenna_height: u32,
}
#[derive(Debug)]
struct TaskConfig {
task_name: String,
task_description: String,
polarization_type: u32,
scan_type: u32,
scan_beam_number: u32,
cut_number: u32,
ray_order: u32,
scan_start_time: i64,
}
#[derive(Debug)]
struct BeamConfig {
cut_index: i16,
tx_beam_index: i16,
rx_beam_elevation: f32,
tx_beam_gain: f32,
rx_beam_width_h: f32,
rx_beam_width_v: f32,
rx_beam_gain: f32,
process_mode: String,
wave_form: String,
n1_prf1: f32,
n1_prf2: f32,
n2_prf1: f32,
n2_prf2: f32,
dealiasing_mode: u32,
azimuth: f32,
start_angle: f32,
end_angle: f32,
angular_resolution: f32,
scan_speed: f32,
log_resolution: f32,
doppler_resolution: f32,
maximum_range1: u32,
maximum_range2: u32,
start_range: u32,
sample1: u32,
sample2: u32,
phase_mode: u32,
atmospheric_loss: f32,
nyquist_speed: f32,
moments_mask: i64,
moments_size_mask: i64,
misc_filter_mask: u32,
sqi_threshold: f32,
sig_threshold: f32,
csr_threshold: f32,
log_threshold: f32,
cpa_threshold: f32,
pmi_threshold: f32,
dplog_threshold: f32,
thresholds_r: [u8; 4],
dbt_mask: u32,
dbz_mask: u32,
velocity_mask: u32,
spectrum_width_mask: u32,
dp_mask: u32,
direction: u32,
ground_clutter_classifier_type: i16,
ground_clutter_filter_type: i16,
ground_clutter_filter_notch_width: i16,
ground_clutter_filter_window: i16,
}
#[derive(Debug)]
struct TypeHeader {
data_type: u32,
scale: u32,
offset: u32,
bin_length: u16,
flags: u16,
length: u32,
}
#[derive(Debug)]
struct RadialData {
radial_state: u32,
spot_blank: u32,
sequence_number: u32,
radial_number: u32,
elevation_number: u32,
azimuth: f32,
elevation: f32,
seconds: i64,
microseconds: u32,
length_of_data: u32,
moment_number: u32,
scan_beam_index: i16,
horizontal_estimated_noise: i16,
vertical_estimated_noise: i16,
prf_flag: u32,
}
#[derive(Debug)]
struct GenericHeader {
magic_number: u32,
major_version: u16,
minor_version: u16,
generic_type: u32,
product_type: u32,
reserved: [u8; 16],
}
#[derive(Debug)]
struct SubPulseConfig {
strategy: u32,
modulation: u32,
frequency: f32,
bandwidth: f32,
width: u32,
horizontal_noise: f32,
vertical_noise: f32,
horizontal_calibration: f32,
vertical_calibration: f32,
horizontal_noise_temperature: f32,
vertical_noise_temperature: f32,
zdr_calibration: f32,
phidp_calibration: f32,
ldr_calibration: f32,
pulse_points: i16,
}
#[derive(Debug)]
struct ScanConfig {
beam_index: u32,
beam_type: u32,
sub_pulse_number: u32,
tx_beam_direction: f32,
tx_beam_width_h: f32,
tx_beam_width_v: f32,
tx_beam_gain: f32,
sub_pulse_configs: Vec<SubPulseConfig>,
}
fn parse_scan_config(input: &[u8]) -> IResult<&[u8], ScanConfig> {
let (input, beam_index) = le_u32(input)?;
let (input, beam_type) = le_u32(input)?;
let (input, sub_pulse_number) = le_u32(input)?;
let (input, tx_beam_direction) = le_f32(input)?;
let (input, tx_beam_width_h) = le_f32(input)?;
let (input, tx_beam_width_v) = le_f32(input)?;
let (input, tx_beam_gain) = le_f32(input)?;
let (input, _) = take(100usize)(input)?; // Skip reserved bytes
// Parse the SubPulseConfigs
let mut sub_pulse_configs = Vec::new();
let mut input = input;
for _ in 0..4 {
let (new_input, sub_pulse_config) = parse_sub_pulse_config(input)?;
input = new_input;
sub_pulse_configs.push(sub_pulse_config);
}
let scan_config = ScanConfig {
beam_index,
beam_type,
sub_pulse_number,
tx_beam_direction,
tx_beam_width_h,
tx_beam_width_v,
tx_beam_gain,
sub_pulse_configs,
};
Ok((input, scan_config))
}
fn parse_sub_pulse_config(input: &[u8]) -> IResult<&[u8], SubPulseConfig> {
let (input, strategy) = le_u32(input)?;
let (input, modulation) = le_u32(input)?;
let (input, frequency) = le_f32(input)?;
let (input, bandwidth) = le_f32(input)?;
let (input, width) = le_u32(input)?;
let (input, horizontal_noise) = le_f32(input)?;
let (input, vertical_noise) = le_f32(input)?;
let (input, horizontal_calibration) = le_f32(input)?;
let (input, vertical_calibration) = le_f32(input)?;
let (input, horizontal_noise_temperature) = le_f32(input)?;
let (input, vertical_noise_temperature) = le_f32(input)?;
let (input, zdr_calibration) = le_f32(input)?;
let (input, phidp_calibration) = le_f32(input)?;
let (input, ldr_calibration) = le_f32(input)?;
let (input, pulse_points) = nom::number::complete::le_i16(input)?;
let (input, _) = take(70usize)(input)?; // Skip reserved bytes
let sub_pulse_config = SubPulseConfig {
strategy,
modulation,
frequency,
bandwidth,
width,
horizontal_noise,
vertical_noise,
horizontal_calibration,
vertical_calibration,
horizontal_noise_temperature,
vertical_noise_temperature,
zdr_calibration,
phidp_calibration,
ldr_calibration,
pulse_points,
};
Ok((input, sub_pulse_config))
}
pub fn parse_raw_data<P: AsRef<Path>>(path: P) -> io::Result<RadarData> {
let path = path.as_ref();
if path.extension().unwrap() == "zip" {
let file = File::open(path).unwrap();
let mut archive = ZipArchive::new(file).unwrap();
let mut file = archive.by_index(0).unwrap();
let mut buf = Vec::new();
file.read_to_end(&mut buf).unwrap();
if &buf[0..4] == b"SSTM" || &buf[16..20] == b"STDM" || &buf[0..4] == b"RSTM" {
return get_radar_data(buf);
} else {
panic!("Invalid file format");
}
} else {
let mut file = File::open(path).unwrap();
let mut buf = Vec::new();
file.read_to_end(&mut buf).unwrap();
if &buf[0..4] == b"SSTM" || &buf[16..20] == b"STDM" || &buf[0..4] == b"RSTM" {
return get_radar_data(buf);
} else {
panic!("Invalid file format");
}
}
}
fn get_radar_data(data: Vec<u8>) -> io::Result<RadarData> {
let total_length = data.len() as u64;
// 使用 Cursor 来处理 Vec<u8>
let mut cursor = Cursor::new(data);
// 读取 GENERIC_HEADER
let mut buffer = vec![0u8; 32];
cursor.read_exact(&mut buffer)?;
let (_, generic_header) = parse_generic_header(&buffer).unwrap();
// 读取 SITE_CONFIG
let mut buffer = vec![0u8; 128];
cursor.read_exact(&mut buffer)?;
let (_, site_config) = parse_site_config(&buffer).unwrap();
// 读取 TASK_CONFIG
let mut buffer = vec![0u8; 256];
cursor.read_exact(&mut buffer)?;
let (_, task_config) = parse_task_config(&buffer).unwrap();
// 读取 SCAN_CONFIG
let mut scan_configs = Vec::new();
for _ in 0..task_config.scan_beam_number {
let mut buffer = vec![0u8; 640];
cursor.read_exact(&mut buffer)?;
let (_, scan_config) = parse_scan_config(&buffer).unwrap();
scan_configs.push(scan_config);
}
// 读取 BEAM_CONFIG
let mut beam_configs = Vec::new();
for _ in 0..task_config.cut_number {
let mut buffer = vec![0u8; 256];
cursor.read_exact(&mut buffer)?;
let (_, beam_config) = parse_beam_config(&buffer).unwrap();
beam_configs.push(beam_config);
}
// 读取 RADIAL_DATA
let (datas, els, azs, ranges) =
parse_final_data(total_length, task_config.cut_number as usize, cursor)?;
// 构建并返回 RadarData 结构体
let radar_data = RadarData {
datetime: task_config.scan_start_time,
els,
azs,
ranges,
datas,
};
Ok(radar_data)
}
fn parse_generic_header(input: &[u8]) -> IResult<&[u8], GenericHeader> {
let (input, magic_number) = le_u32(input)?;
let (input, major_version) = le_u16(input)?;
let (input, minor_version) = le_u16(input)?;
let (input, generic_type) = le_u32(input)?;
let (input, product_type) = le_u32(input)?;
let (input, reserved) = take(16usize)(input)?;
let generic_header = GenericHeader {
magic_number,
major_version,
minor_version,
generic_type,
product_type,
reserved: reserved.try_into().unwrap(),
};
Ok((input, generic_header))
}
fn parse_site_config(input: &[u8]) -> IResult<&[u8], SiteConfig> {
let (input, site_code) = take(8usize)(input)?;
let (input, site_name) = take(32usize)(input)?;
let (input, latitude) = le_f32(input)?;
let (input, longitude) = le_f32(input)?;
let (input, antenna_height) = le_u32(input)?;
let (input, _) = take(4usize)(input)?; // Skip reserved bytes
let site_config = SiteConfig {
site_code: String::from_utf8(site_code.to_vec())
.unwrap()
.trim_end_matches('\0')
.to_string(),
site_name: String::from_utf8(site_name.to_vec())
.unwrap()
.trim_end_matches('\0')
.to_string(),
latitude,
longitude,
antenna_height,
};
Ok((input, site_config))
}
fn parse_task_config(input: &[u8]) -> IResult<&[u8], TaskConfig> {
let (input, task_name) = take(32usize)(input)?;
let (input, task_description) = take(128usize)(input)?;
let (input, polarization_type) = le_u32(input)?;
let (input, scan_type) = le_u32(input)?;
let (input, scan_beam_number) = le_u32(input)?;
let (input, cut_number) = le_u32(input)?;
let (input, ray_order) = le_u32(input)?;
let (input, scan_start_time) = le_i64(input)?;
let (input, _) = take(68usize)(input)?; // Skip reserved bytes
let task_config = TaskConfig {
task_name: String::from_utf8_lossy(task_name).to_string(),
task_description: String::from_utf8_lossy(task_description).to_string(),
polarization_type,
scan_type,
scan_beam_number,
cut_number,
ray_order,
scan_start_time,
};
Ok((input, task_config))
}
fn single_beam_block(raw: &[u8], bin_length: usize) -> io::Result<Vec<f64>> {
let raw = match bin_length {
1 => {
let new_raw: Vec<f64> = raw.into_iter().map(|v| *v as f64).collect();
new_raw
}
2 => {
let new_raw: Vec<f64> = cast_slice(&raw)
.into_iter()
.map(|v: &u16| *v as f64)
.collect();
new_raw
}
4 => {
let new_raw: Vec<f64> = cast_slice(&raw)
.into_iter()
.map(|v: &u32| *v as f64)
.collect();
new_raw
}
8 => {
let new_raw: Vec<f64> = cast_slice(&raw)
.into_iter()
.map(|v: &u64| *v as f64)
.collect();
new_raw
}
_ => {
let new_raw: Vec<f64> = raw.into_iter().map(|v| *v as f64).collect();
new_raw
}
};
Ok(raw)
}
fn beam_block_exact(cursor: &mut Cursor<Vec<u8>>, header: &TypeHeader) -> io::Result<Vec<u8>> {
let mut buf = vec![0u8; header.length as usize];
cursor.read_exact(&mut buf)?;
Ok(buf)
}
fn data_type(typ: u32) -> &'static str {
match typ {
2 => "DBZ",
3 => "VEL",
4 => "SW",
7 => "ZDR",
9 => "CC",
10 => "PHIDP",
11 => "KDP",
_ => "Unknown",
}
}
fn parse_final_data(
all_length: u64,
cut_number: usize,
mut cursor: Cursor<Vec<u8>>,
) -> io::Result<(
HashMap<&'static str, Vec<f64>>,
Vec<f64>,
Vec<f64>,
Vec<f64>,
)> {
let position = cursor.position();
let mut radial_buffer = vec![0u8; 128];
let mut header_buffer = vec![0u8; 32];
cursor.read_exact(&mut radial_buffer)?;
// First Block
let (_, radial_data) = parse_radial_data(&radial_buffer).unwrap();
// Radial_number: I don't know why not use it.
// let radial_number = radial_data.radial_number as usize;
// 变量类型
let type_number = radial_data.moment_number as usize;
let mut gate_len = vec![0; type_number];
let mut types = vec!["Unknown"; type_number];
// final datas
let mut datas = HashMap::new();
for idx in 0..type_number {
cursor.read_exact(&mut header_buffer)?;
let (_, header) = parse_type_header(&header_buffer).unwrap();
let first_beam_block = beam_block_exact(&mut cursor, &header)?;
let first_beam = single_beam_block(&first_beam_block, header.bin_length as usize)?;
gate_len[idx] = first_beam.len();
let data_type = data_type(header.data_type);
if data_type == "Unknown" {
continue;
}
types[idx] = data_type;
}
let first_block_position = cursor.position();
let roll_num = (all_length - position) / (first_block_position - position);
let azm_number = (roll_num / cut_number as u64) as usize;
for idx in 0..type_number {
if types[idx] == "Unknown" {
continue;
}
datas.insert(
types[idx],
vec![0f64; cut_number * azm_number * gate_len[idx]],
);
}
// Reset Cursor
cursor.set_position(position);
let mut els = vec![0f64; cut_number];
let mut azs = vec![0f64; azm_number];
for e in 0..cut_number {
for a in 0..azm_number {
cursor.read_exact(&mut radial_buffer)?;
let (_, radial_data) = parse_radial_data(&radial_buffer).unwrap();
els[e] = radial_data.elevation as f64;
azs[a] = radial_data.azimuth as f64;
let type_number = radial_data.moment_number as usize;
for typ in 0..type_number {
cursor.read_exact(&mut header_buffer)?;
let (_, header) = parse_type_header(&header_buffer).unwrap();
let beam_block = beam_block_exact(&mut cursor, &header)?;
let mut beam = single_beam_block(&beam_block, header.bin_length as usize)?;
beam.iter_mut()
.for_each(|v| *v = (*v - header.offset as f64) / header.scale as f64);
let typ_name = types.get(typ).unwrap();
if typ_name == &"Unknown" {
continue;
}
let e = radial_data.elevation_number as usize - 1;
datas.get_mut(typ_name).unwrap()[e * (azm_number * gate_len[typ])
+ a * gate_len[typ]
..e * (azm_number * gate_len[typ]) + (a + 1) * gate_len[typ]]
.copy_from_slice(&beam);
}
}
}
let mut ranges = vec![0f64; gate_len[0]];
ranges
.iter_mut()
.enumerate()
.for_each(|(idx, r)| *r = idx as f64 * 30.0);
Ok((datas, els, azs, ranges))
}
fn parse_beam_config(input: &[u8]) -> IResult<&[u8], BeamConfig> {
let (input, cut_index) = le_i16(input)?;
let (input, tx_beam_index) = le_i16(input)?;
let (input, rx_beam_elevation) = le_f32(input)?;
let (input, tx_beam_gain) = le_f32(input)?;
let (input, rx_beam_width_h) = le_f32(input)?;
let (input, rx_beam_width_v) = le_f32(input)?;
let (input, rx_beam_gain) = le_f32(input)?;
let (input, process_mode) = map(le_u32, |v| match v {
1 => "PPP".to_string(),
2 => "FFT".to_string(),
_ => "Unknown".to_string(),
})(input)?;
let (input, wave_form) = map(le_u32, |v| match v {
0 => "CS连续监测".to_string(),
1 => "CD连续多普勒".to_string(),
2 => "CDX多普勒扩展".to_string(),
3 => "Rx Test".to_string(),
4 => "BATCH批模式".to_string(),
5 => "Dual PRF双PRF".to_string(),
6 => "Staggered PRT 参差PRT".to_string(),
_ => "Unknown".to_string(),
})(input)?;
let (input, n1_prf1) = le_f32(input)?;
let (input, n1_prf2) = le_f32(input)?;
let (input, n2_prf1) = le_f32(input)?;
let (input, n2_prf2) = le_f32(input)?;
let (input, dealiasing_mode) = le_u32(input)?;
let (input, azimuth) = le_f32(input)?;
let (input, start_angle) = le_f32(input)?;
let (input, end_angle) = le_f32(input)?;
let (input, angular_resolution) = le_f32(input)?;
let (input, scan_speed) = le_f32(input)?;
let (input, log_resolution) = le_f32(input)?;
let (input, doppler_resolution) = le_f32(input)?;
let (input, maximum_range1) = le_u32(input)?;
let (input, maximum_range2) = le_u32(input)?;
let (input, start_range) = le_u32(input)?;
let (input, sample1) = le_u32(input)?;
let (input, sample2) = le_u32(input)?;
let (input, phase_mode) = le_u32(input)?;
let (input, atmospheric_loss) = le_f32(input)?;
let (input, nyquist_speed) = le_f32(input)?;
let (input, moments_mask) = le_i64(input)?;
let (input, moments_size_mask) = le_i64(input)?;
let (input, misc_filter_mask) = le_u32(input)?;
let (input, sqi_threshold) = le_f32(input)?;
let (input, sig_threshold) = le_f32(input)?;
let (input, csr_threshold) = le_f32(input)?;
let (input, log_threshold) = le_f32(input)?;
let (input, cpa_threshold) = le_f32(input)?;
let (input, pmi_threshold) = le_f32(input)?;
let (input, dplog_threshold) = le_f32(input)?;
let (input, thresholds_r) = take(4usize)(input)?;
let (input, dbt_mask) = le_u32(input)?;
let (input, dbz_mask) = le_u32(input)?;
let (input, velocity_mask) = le_u32(input)?;
let (input, spectrum_width_mask) = le_u32(input)?;
let (input, dp_mask) = le_u32(input)?;
let (input, direction) = le_u32(input)?;
let (input, ground_clutter_classifier_type) = le_i16(input)?;
let (input, ground_clutter_filter_type) = le_i16(input)?;
let (input, ground_clutter_filter_notch_width) = le_i16(input)?;
let (input, ground_clutter_filter_window) = le_i16(input)?;
let (input, _) = take(44usize)(input)?;
let beam_config = BeamConfig {
cut_index,
tx_beam_index,
rx_beam_elevation,
tx_beam_gain,
rx_beam_width_h,
rx_beam_width_v,
rx_beam_gain,
process_mode,
wave_form,
n1_prf1,
n1_prf2,
n2_prf1,
n2_prf2,
dealiasing_mode,
azimuth,
start_angle,
end_angle,
angular_resolution,
scan_speed,
log_resolution,
doppler_resolution,
maximum_range1,
maximum_range2,
start_range,
sample1,
sample2,
phase_mode,
atmospheric_loss,
nyquist_speed,
moments_mask,
moments_size_mask,
misc_filter_mask,
sqi_threshold,
sig_threshold,
csr_threshold,
log_threshold,
cpa_threshold,
pmi_threshold,
dplog_threshold,
thresholds_r: thresholds_r.try_into().unwrap(),
dbt_mask,
dbz_mask,
velocity_mask,
spectrum_width_mask,
dp_mask,
direction,
ground_clutter_classifier_type,
ground_clutter_filter_type,
ground_clutter_filter_notch_width,
ground_clutter_filter_window,
};
Ok((input, beam_config))
}
fn parse_radial_data(input: &[u8]) -> IResult<&[u8], RadialData> {
let (input, radial_state) = le_u32(input)?;
let (input, spot_blank) = le_u32(input)?;
let (input, sequence_number) = le_u32(input)?;
let (input, radial_number) = le_u32(input)?;
let (input, elevation_number) = le_u32(input)?;
let (input, azimuth) = le_f32(input)?;
let (input, elevation) = le_f32(input)?;
let (input, seconds) = le_i64(input)?;
let (input, microseconds) = le_u32(input)?;
let (input, length_of_data) = le_u32(input)?;
let (input, moment_number) = le_u32(input)?;
let (input, scan_beam_index) = le_i16(input)?;
let (input, horizontal_estimated_noise) = le_i16(input)?;
let (input, vertical_estimated_noise) = le_i16(input)?;
let (input, prf_flag) = le_u32(input)?;
let (input, _) = take(70usize)(input)?; // Skip reserved bytes
let radial_data = RadialData {
radial_state,
spot_blank,
sequence_number,
radial_number,
elevation_number,
azimuth,
elevation,
seconds,
microseconds,
length_of_data,
moment_number,
scan_beam_index,
horizontal_estimated_noise,
vertical_estimated_noise,
prf_flag,
};
Ok((input, radial_data))
}
fn parse_type_header(input: &[u8]) -> IResult<&[u8], TypeHeader> {
let (input, data_type) = le_u32(input)?;
let (input, scale) = le_u32(input)?;
let (input, offset) = le_u32(input)?;
let (input, bin_length) = le_u16(input)?;
let (input, flags) = le_u16(input)?;
let (input, length) = le_u32(input)?;
let (input, _) = take(12usize)(input)?; // Skip reserved bytes
let type_header = TypeHeader {
data_type,
scale,
offset,
bin_length,
flags,
length,
};
Ok((input, type_header))
}
mod test {
use crate::raw::parse_raw_data;
use super::get_radar_data;
#[test]
fn test() {
use std::fs::File;
let radar_data = parse_raw_data(
"/Users/tsuki/Desktop/Z_RADR_I_X5775_20230726180000_O_DOR-XPD-CAP-FMT.BIN.zip",
)
.unwrap();
}
}

View File

@ -94,4 +94,4 @@ path = "../radarg_core"
[dependencies.adw]
package = "libadwaita"
version = "0.7.0"
features = ["v1_4"]
features = ["v1_5"]

View File

@ -4,43 +4,35 @@ use super::{
messages::{MonitorInputMsg, MonitorOutputMsg},
monitor::MonitorModel,
setting::SettingModel,
sidebar::{SideBarInputMsg, SideBarModel},
ControlPanelOutputMsg, TimelineMsg,
};
use crate::components::sidebar::{SideBarInputMsg, SideBarModel};
use crate::datapool::{DataPool, Value};
use crate::predefined::color_mapper::{BoundaryNorm, ColorMapper, ColorMapperComb, Discrete};
use crate::widgets::{DynamicCol, ElementType};
use crate::{plugin_system::init_plugin, widgets::render::Layer, PLUGIN_MANAGER};
use abi_stable::std_types::RStr;
use adw::prelude::*;
use chrono::{prelude::*, Duration};
use futures::future::BoxFuture;
use gi::App;
use gtk::glib;
use gtk::glib::clone;
use gtk::prelude::*;
use ndarray::{ArrayView1, ArrayViewD};
use once_cell::sync::Lazy;
use radarg_core::Data;
use relm4::actions::{AccelsPlus, RelmAction, RelmActionGroup};
use relm4::*;
use relm4::{gtk, Component, ComponentParts, ComponentSender, RelmWidgetExt, SimpleComponent};
use relm4::{
actions::{AccelsPlus, RelmAction, RelmActionGroup},
adw::{self, prelude::*, MessageDialog},
gtk::{self, glib, glib::clone, prelude::*},
view, Component, ComponentController, ComponentParts, ComponentSender, Controller,
RelmWidgetExt, SimpleComponent,
};
use relm4_components::open_dialog::{
OpenDialog, OpenDialogMsg, OpenDialogResponse, OpenDialogSettings,
};
use smallvec::SmallVec;
use std::marker::PhantomData;
use std::num::NonZeroU32;
use std::{
any::Any,
cell::RefCell,
collections::{BTreeMap, HashMap},
path::PathBuf,
rc::Rc,
sync::{Arc, Mutex},
};
use tokio::{sync::oneshot, task};
use tracing::{debug, error, info, warn};
use tracing::*;
use tracing_subscriber::fmt::layer;
relm4::new_action_group!(FileActionGroup, "file");
@ -69,9 +61,10 @@ pub enum FileIOType {
pub enum AppMsg {
Refresh,
FileIO { typ: FileIOType },
OpenDialog,
CloseRequest,
Close,
OpenDialog,
OpenFileDialog,
}
#[tracker::track]
pub struct AppModel {
@ -186,6 +179,22 @@ impl Component for AppModel {
setting_stack_page = view_stack.add_titled(model.setting.widget(), Some("setting"), "Setting") -> adw::ViewStackPage{
set_icon_name:Some("settings-filled")
},
#[name="dialog"]
adw::Dialog {
set_title: "Dialog",
set_presentation_mode: adw::DialogPresentationMode::Floating,
set_follows_content_size: true,
set_can_close: true,
#[wrap(Some)]
set_child=&gtk::Box{
set_height_request: 200,
set_width_request: 200,
gtk::Label{
set_text:"Dialog",
},
}
}
}
menu! {
@ -241,7 +250,11 @@ impl Component for AppModel {
move |model_message| match model_message {
MonitorOutputMsg::Attached(new_module) => {
sidebar_sender.emit(SideBarInputMsg::Package(new_module));
AppMsg::Close
AppMsg::OpenDialog
// AppMsg::Close
}
MonitorOutputMsg::Fc => {
AppMsg::OpenDialog
}
_ => AppMsg::Close,
}
@ -305,7 +318,7 @@ impl Component for AppModel {
// register_layer_actions(&widgets.main_window, sender.clone());
let action: RelmAction<OpenAction> = {
RelmAction::new_stateless(move |_| {
sender.input(AppMsg::OpenDialog);
sender.input(AppMsg::OpenFileDialog);
})
};
group.add_action(action);
@ -327,9 +340,12 @@ impl Component for AppModel {
relm4::main_application().quit();
}
AppMsg::Close => {}
AppMsg::OpenDialog => {
AppMsg::OpenFileDialog => {
self.open_dialog.emit(OpenDialogMsg::Open);
}
AppMsg::OpenDialog => {
widgets.dialog.present(Some(root));
}
AppMsg::FileIO {
typ: FileIOType::Open(data),
} => self.render.emit(MonitorInputMsg::PushData(data)),

View File

@ -22,6 +22,7 @@ impl Debug for MonitorInputMsg {
#[derive(Debug)]
pub enum MonitorOutputMsg {
Attached(Rc<RefCell<ModulePackage>>),
Fc,
}
#[derive(Debug)]

View File

@ -95,19 +95,20 @@ impl Component for MonitorModel {
self.reset();
match message {
MonitorInputMsg::PushData(data) => {
widgets
.renderer
.get_gi(|gi| match gi.load_data(&data, &SETTING) {
Ok(package) => {
info!("data load success!");
let rc_package = Rc::new(RefCell::new(package));
self.set_module_packages(vec![rc_package.clone()]);
sender.output(MonitorOutputMsg::Attached(rc_package));
}
Err(err) => {
error!("Load Error, cause of {}", err);
}
})
sender.output(MonitorOutputMsg::Fc);
// widgets
// .renderer
// .get_gi(|gi| match gi.load_data(&data, &SETTING) {
// Ok(package) => {
// info!("data load success!");
// let rc_package = Rc::new(RefCell::new(package));
// self.set_module_packages(vec![rc_package.clone()]);
// sender.output(MonitorOutputMsg::Attached(rc_package));
// }
// Err(err) => {
// error!("Load Error, cause of {}", err);
// }
// })
}
MonitorInputMsg::QueueDraw => {
widgets.renderer.queue_draw();

View File

@ -16,8 +16,12 @@ use std::{
};
fn compute_plugin_path(base_name: &str) -> io::Result<PathBuf> {
let debug_dir = "./target/debug".as_ref_::<Path>().into_::<PathBuf>();
let release_dir = "./target/release".as_ref_::<Path>().into_::<PathBuf>();
let debug_dir = "./loaders/target/debug"
.as_ref_::<Path>()
.into_::<PathBuf>();
let release_dir = "./loaders/target/release"
.as_ref_::<Path>()
.into_::<PathBuf>();
let debug_path = RawLibrary::path_in_directory(&debug_dir, base_name, LibrarySuffix::NoSuffix);

View File

@ -190,6 +190,8 @@ impl GLAreaImpl for Render {
impl Render {
fn ensure_canvas(&self) {
use gi::{App as GI, Helper, GL};
let widget = self.obj();
widget.attach_buffers();
if self.gi.borrow().is_none() {
info!("Creating canvas");
let (mut gi, viewport) = unsafe {

View File

@ -63,7 +63,11 @@ impl Setting {
name, cmap,
{DBZ => "DBZ"},
{V => "VEL"},
{VIL => "VIL"}
{VIL => "VIL"},
{CC => "CC"},
{KDP => "KDP"},
{ZDR => "ZDR"},
{PHIDP => "PHIDP"}
)
}
}

View File

@ -155,6 +155,7 @@ macro_rules! raw2new {
fn from(raw: RawRadarGridData) -> Self {
let RawRadarGridData { data, info } = raw;
let shape = info.shape.into_vec();
println!("{:?}", shape);
let data = match data {
$(