【Rust】緯度経度のcsvデータを読み込んで2点間の距離を求める


背景

500点くらいの位置情報がcsvデータにまとめられていて、その全ての組み合わせについて直線距離(km) を求めたい.

緯度経度から距離を求める

以下の記事を参考にさせていただきました.

pub fn cal_rho(lat_a: &f64, lon_a: &f64, lat_b: &f64, lon_b: &f64) -> f64 {
    const RA: f64 = 6378.140; // equatorial radius (km)
    const RB: f64 = 6356.755; // polar radius (km)
    let f: f64;
    let rad_lat_a: f64;
    let rad_lon_a: f64;
    let rad_lat_b: f64;
    let rad_lon_b: f64;
    let pa: f64;
    let pb: f64;
    let xx: f64;
    let c1: f64;
    let c2: f64;
    let dr: f64;
    let rho: f64;

    f = (RA - RB) / RA;
    rad_lat_a = lat_a.to_radians();
    rad_lon_a = lon_a.to_radians();
    rad_lat_b = lat_b.to_radians();
    rad_lon_b = lon_b.to_radians();
    pa = (RB / RA * rad_lat_a.tan()).atan();
    pb = (RB / RA * rad_lat_b.tan()).atan();
    xx = (pa.sin() * pb.sin() + pa.cos() * pb.cos() * (rad_lon_a - rad_lon_b).cos()).acos();
    c1 = ((xx.sin() - xx) * (pa.sin() + pb.sin())).powf(2.0) / ((xx / 2.0).cos()).powf(2.0);
    c2 = ((xx.sin() + xx) * (pa.sin() - pb.sin())).powf(2.0) / ((xx / 2.0).sin()).powf(2.0);
    dr = f / 8.0 * (c1 - c2);
    rho = RA * (xx + dr);
    rho
}

csvの読み込み -> 距離の計算

rdr.records() で取得できる StringRecordsIter を使ってネストのループを作ろうと思ったが、うまく行かなかった.
そのため Iter -> Vec に変換して対応した.

extern crate csv;
use csv::StringRecord;
use std::env;
use std::error::Error;
use std::ffi::OsString;
use std::fs::File;

pub fn run() -> Result<(), Box<Error>> {
    let file_path = "file.csv";
    let file = File::open(file_path)?;
    let mut rdr = csv::Reader::from_reader(file);
    let _records = rdr.records();
    let records: Vec<StringRecord> = _records.map(|x| x.unwrap()).collect();
    let data_len = &records.len();

    for i in 0..*data_len {
        for j in 0..*data_len {
            let r_i = &records[i];
            let lat_i = &r_i[1];
            let lat_i: f64 = lat_i.parse().unwrap();
            let lng_i = &r_i[2];
            let lng_i: f64 = lng_i.parse().unwrap();
            let r_j = &records[j];
            let lat_j = &r_j[1];
            let lat_j: f64 = lat_j.parse().unwrap();
            let lng_j = &r_j[2];
            let lng_j: f64 = lng_j.parse().unwrap();

            let dist = cal_rho(&lat_i, &lng_i, &lat_j, &lng_j);

            println!("{}", dist);
        }
    }
    Ok(())
}

手探りの実装ですので、良い方法あればアドバイスお待ちしています。