Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
use super::funejson::Value; ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::geo_distance::distance; ← from geo.distance ^1.0.0 · built alongside by fune
use super::geo_point_in_polygon::{geo_point_from_value, GeoPoint}; ← from geo.point-in-polygon ^1.0.0 · built alongside by fune
/// Great-circle length of a route through the stops in order, leg by leg,
/// optionally closing back to the first stop.
///
/// # Panics
/// Panics on an empty list or a coordinate out of range.
pub fn route_distance(stops: &[GeoPoint], return_to_start: bool) -> RouteDistance {
if stops.is_empty() {
panic!("stops must not be empty");
}
let mut leg_metres: Vec<f64> = Vec::new();
// Each leg is a whole number of millimetres; adding them as integers and
// dividing once avoids floating-point drift (and is the same double everywhere).
let mut total_millimetres: i64 = 0;
let mut add_leg = |a: &GeoPoint, b: &GeoPoint| {
let metres = distance(a.lat, a.lng, b.lat, b.lng);
leg_metres.push(metres);
total_millimetres += (metres * 1000.0 + 0.5).floor() as i64;
};
for i in 1..stops.len() {
add_leg(&stops[i - 1], &stops[i]);
}
if return_to_start && stops.len() > 1 {
add_leg(&stops[stops.len() - 1], &stops[0]);
}
RouteDistance {
total_metres: total_millimetres as f64 / 1000.0,
leg_metres,
}
}
pub fn route_distance_to_value(r: &RouteDistance) -> Value {
Value::obj(vec![
("totalMetres", Value::Float(r.total_metres)),
("legMetres", Value::Arr(r.leg_metres.iter().map(|m| Value::Float(*m)).collect())),
])
}
pub fn fune_vector(args: &[Value]) -> Value {
let stops: Vec<GeoPoint> = args[0].as_arr().iter().map(geo_point_from_value).collect();
route_distance_to_value(&route_distance(&stops, args[1].as_bool()))
}