Commit inicial: splat-rs — fork/port a Rust de SPLAT!

Fork de SPLAT! (John A. Magliacane, KD2BD, 2002-2014), bajo GPLv2 heredada
del original. El núcleo de cálculo de propagación (ITWOM v3.0, Sid Shumate)
se mantiene sin modificar en cpp/itwom3.0.cpp, llamado vía FFI. El resto
del pipeline (lectura de formatos SPLAT!, reportes, mapas, KML, gnuplot)
se reescribió en Rust, con paralelización nativa vía rayon reemplazando
el paralelismo por múltiples procesos del original. Validado contra el
corpus golden de SPLAT! con drift < 0.02 dB en cálculos ITWOM.
This commit is contained in:
2026-08-23 01:50:41 -05:00
commit 9d7d3bac45
46 changed files with 9883 additions and 0 deletions
+77
View File
@@ -0,0 +1,77 @@
// C ABI wrapper around the C++ ITWOM entry points so Rust can FFI them
// cleanly. The C++ originals take `double &` / `int &` reference params,
// which have no C equivalent; we translate them to pointers.
#include <cstring>
extern void point_to_point(double elev[], double tht_m, double rht_m,
double eps_dielect, double sgm_conductivity, double eno_ns_surfref,
double frq_mhz, int radio_climate, int pol, double conf, double rel,
double &dbloss, char *strmode, int &errnum);
extern void point_to_point_ITM(double elev[], double tht_m, double rht_m,
double eps_dielect, double sgm_conductivity, double eno_ns_surfref,
double frq_mhz, int radio_climate, int pol, double conf, double rel,
double &dbloss, char *strmode, int &errnum);
extern double ITWOMVersion();
extern "C" {
// The C++ point_to_point / point_to_point_ITM signatures are non-const on
// `elev`, but by inspection of itwom3.0.cpp neither routine writes into
// the elev array — they only read samples (and use scratch space held in
// the thread_local statics we patched in). Passing the caller's buffer
// directly avoids a per-call heap alloc + memcpy that otherwise dominates
// a full map sweep at ~200 M invocations.
//
// If a future upstream update to ITWOM starts mutating `elev`, Rust's
// ownership guarantees still hold: the elev_buf in compute_radial gets
// cleared and refilled at the top of every ITWOM call, so mid-call
// scribbles would be overwritten before being observed.
void splat_point_to_point(double* elev, double tht_m, double rht_m,
double eps_dielect, double sgm_conductivity, double eno_ns_surfref,
double frq_mhz, int radio_climate, int pol, double conf, double rel,
double* dbloss, char* strmode, int strmode_len, int* errnum)
{
double loss = 0.0;
int err = 0;
char mode[64] = {0};
point_to_point(elev, tht_m, rht_m, eps_dielect, sgm_conductivity,
eno_ns_surfref, frq_mhz, radio_climate, pol, conf, rel,
loss, mode, err);
*dbloss = loss;
*errnum = err;
if (strmode && strmode_len > 0) {
std::strncpy(strmode, mode, (size_t)strmode_len - 1);
strmode[strmode_len - 1] = '\0';
}
}
void splat_point_to_point_itm(double* elev, double tht_m, double rht_m,
double eps_dielect, double sgm_conductivity, double eno_ns_surfref,
double frq_mhz, int radio_climate, int pol, double conf, double rel,
double* dbloss, char* strmode, int strmode_len, int* errnum)
{
double loss = 0.0;
int err = 0;
char mode[64] = {0};
point_to_point_ITM(elev, tht_m, rht_m, eps_dielect, sgm_conductivity,
eno_ns_surfref, frq_mhz, radio_climate, pol, conf, rel,
loss, mode, err);
*dbloss = loss;
*errnum = err;
if (strmode && strmode_len > 0) {
std::strncpy(strmode, mode, (size_t)strmode_len - 1);
strmode[strmode_len - 1] = '\0';
}
}
double splat_itwom_version() { return ITWOMVersion(); }
} // extern "C"