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::charts_shape_line_path::svg_pair; ← linePath, another function of this group · built into the same file, even by a slim install
use super::math_sin_cos::sin_cos; ← from math.sin-cos ^1.0.0 · built alongside by fune
const PI: f64 = 3.141592653589793;
const TAU: f64 = 6.283185307179586;
fn arc_point(arc: &Arc, r: f64, angle: f64) -> String {
let sc = sin_cos(angle);
svg_pair(arc.cx + r * sc.sin, arc.cy - r * sc.cos)
}
fn arc_to(arc: &Arc, r: f64, large: i64, sweep: i64, angle: f64) -> String {
format!("A{},0,{},{},{}", svg_pair(r, r), large, sweep, arc_point(arc, r, angle))
}
/// An annular sector as SVG path data. Angles are radians from 12 o'clock,
/// clockwise, as in d3.arc. See the README for the exact path format.
///
/// # Panics
/// Panics unless 0 <= innerRadius <= outerRadius.
pub fn arc_path(arc: &Arc) -> String {
let (ri, ro, a0, a1) = (arc.inner_radius, arc.outer_radius, arc.start_angle, arc.end_angle);
if !(ri >= 0.0) || !(ro >= ri) {
panic!("arc radii must satisfy 0 <= innerRadius <= outerRadius, received {} and {}", ri, ro);
}
let span = a1 - a0;
if span == 0.0 || ro == 0.0 {
return String::new();
}
let sweep = if span > 0.0 { 1 } else { 0 };
let back = 1 - sweep;
let dir = if span > 0.0 { 1.0 } else { -1.0 };
if span.abs() >= TAU {
// One SVG arc cannot start and end at the same point, so a full turn is
// two half turns; the hole is drawn the other way so it stays empty.
let half = a0 + dir * PI;
let mut out = format!(
"M{}{}{}Z",
arc_point(arc, ro, a0),
arc_to(arc, ro, 1, sweep, half),
arc_to(arc, ro, 1, sweep, a0)
);
if ri > 0.0 {
let other = a0 - dir * PI;
out.push_str(&format!(
"M{}{}{}Z",
arc_point(arc, ri, a0),
arc_to(arc, ri, 1, back, other),
arc_to(arc, ri, 1, back, a0)
));
}
return out;
}
let large = if span.abs() > PI { 1 } else { 0 };
let mut out = format!("M{}{}", arc_point(arc, ro, a0), arc_to(arc, ro, large, sweep, a1));
if ri > 0.0 {
out.push_str(&format!("L{}{}", arc_point(arc, ri, a1), arc_to(arc, ri, large, back, a0)));
} else {
out.push_str(&format!("L{}", svg_pair(arc.cx, arc.cy)));
}
out.push('Z');
out
}
pub fn fune_vector(args: &[Value]) -> Value {
let a = &args[0];
let arc = Arc {
cx: a.get("cx").as_f64(),
cy: a.get("cy").as_f64(),
inner_radius: a.get("innerRadius").as_f64(),
outer_radius: a.get("outerRadius").as_f64(),
start_angle: a.get("startAngle").as_f64(),
end_angle: a.get("endAngle").as_f64(),
};
Value::str(&arc_path(&arc))
}