Skip to content

Instantly share code, notes, and snippets.

@SaitoAtsushi
Created July 4, 2020 14:22
Show Gist options
  • Save SaitoAtsushi/01a3db74c51ac06001dbfadfc9bebaf3 to your computer and use it in GitHub Desktop.
Save SaitoAtsushi/01a3db74c51ac06001dbfadfc9bebaf3 to your computer and use it in GitHub Desktop.
# Qiita で見た題材を Rust らしく整理
# 元ネタ → https://qiita.com/fltwtn/items/7ca55afd3f648ca63281
[package]
name = "geodetic"
version = "0.1.0"
authors = ["SAITO Atsushi <[email protected]>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[[bin]]
name = "geodetic"
path = "./main.rs"
[dependencies]
csv = "1.1.3"
serde = {version = "1.0.114", features = ["derive"]}
#[derive(serde::Deserialize)]
pub struct GeodeticCoordinates {
pub name: std::string::String,
longitude: f64,
latitude: f64,
}
impl GeodeticCoordinates {
const RA: f64 = 6378.140;
const RB: f64 = 6356.755;
fn parametric_latitude(&self) -> f64 {
(Self::RB / Self::RA * self.latitude.to_radians().tan()).atan()
}
fn geodetic_distance(&self, rhs: &Self) -> f64 {
let pa = self.parametric_latitude();
let pb = rhs.parametric_latitude();
let xx = (pa.sin() * pb.sin()
+ pa.cos()
* pb.cos()
* (self.longitude.to_radians() - rhs.longitude.to_radians()).cos())
.acos();
let c1 = ((xx.sin() - xx) * (pa.sin() + pb.sin())).powf(2.0) / (xx / 2.0).cos().powf(2.0);
let c2 = ((xx.sin() + xx) * (pa.sin() - pb.sin())).powf(2.0) / (xx / 2.0).sin().powf(2.0);
let dr = ((Self::RA - Self::RB) / Self::RA) / 8.0 * (c1 - c2);
Self::RA * (xx + dr)
}
}
extern crate csv;
trait CoordinatesReader {
fn read(&self) -> Result<Vec<GeodeticCoordinates>, csv::Error>;
}
impl CoordinatesReader for std::fs::File {
fn read(&self) -> Result<Vec<GeodeticCoordinates>, csv::Error> {
csv::Reader::from_reader(self).deserialize().collect()
}
}
trait ForEachPair: Clone + Iterator {
fn for_each_pair<F: Fn(&Self::Item, &Self::Item)>(&mut self, f: F) {
while let Some(ref i) = self.next() {
self.clone().for_each(|ref j| f(&i, &j));
}
}
}
impl<T: Iterator + Clone> ForEachPair for T {}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let file = std::fs::File::open("file.csv")?;
let records = file.read()?;
println!(" Location A | Location B | Distance");
println!("---------------+----------------+---------");
records.iter().for_each_pair(|&i, &j| {
println!(
" {: <14}| {: <14} | {:8.3}",
i.name,
j.name,
i.geodetic_distance(j)
)
});
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment