背景
500点くらいの位置情報がcsvデータにまとめられていて、その全ての組み合わせについて直線距離(km) を求めたい.
緯度経度から距離を求める
以下の記事を参考にさせていただきました.
- Python 経度・緯度で与えられた2点間距離計算
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(())
}
手探りの実装ですので、良い方法あればアドバイスお待ちしています。