use super::GraphMaker;
use std::fmt::Write;
pub struct Shapes {
edge_color: String, face_color: String, line_width: f64, arrow_scale: f64, arrow_style: String, buffer: String, }
impl Shapes {
pub fn new() -> Self {
Shapes {
edge_color: String::new(),
face_color: String::new(),
line_width: 0.0,
arrow_scale: 0.0,
arrow_style: String::new(),
buffer: String::new(),
}
}
pub fn draw_arc<T>(&mut self, xc: T, yc: T, r: T, ini_angle: T, fin_angle: T)
where
T: std::fmt::Display,
{
let opt = self.options_shared();
write!(
&mut self.buffer,
"p=pat.Arc(({},{}),2*{},2*{},theta1={},theta2={},angle=0{})\n\
plt.gca().add_patch(p)\n",
xc, yc, r, r, ini_angle, fin_angle, &opt
)
.unwrap();
}
pub fn draw_arrow<T>(&mut self, xi: T, yi: T, xf: T, yf: T)
where
T: std::fmt::Display,
{
let opt_shared = self.options_shared();
let opt_arrow = self.options_arrow();
write!(
&mut self.buffer,
"p=pat.FancyArrowPatch(({},{}),({},{})\
,shrinkA=0,shrinkB=0\
,path_effects=[pff.Stroke(joinstyle='miter')]\
{}{})\n\
plt.gca().add_patch(p)\n",
xi, yi, xf, yf, &opt_shared, &&opt_arrow,
)
.unwrap();
}
pub fn draw_circle<T>(&mut self, xc: T, yc: T, r: T)
where
T: std::fmt::Display,
{
let opt = self.options_shared();
write!(
&mut self.buffer,
"p=pat.Circle(({},{}),{}{})\n\
plt.gca().add_patch(p)\n",
xc, yc, r, &opt
)
.unwrap();
}
pub fn draw_polyline<T>(&mut self, points: &Vec<Vec<T>>, closed: bool)
where
T: std::fmt::Display,
{
let mut first = true;
for p in points {
if first {
write!(&mut self.buffer, "dat=[[pth.Path.MOVETO,({},{})]", p[0], p[1]).unwrap();
} else {
write!(&mut self.buffer, ",[pth.Path.LINETO,({},{})]", p[0], p[1]).unwrap();
}
first = false;
}
if closed {
write!(&mut self.buffer, ",[pth.Path.CLOSEPOLY,(None,None)]").unwrap();
}
let opt = self.options_shared();
write!(&mut self.buffer, "]\n").unwrap();
write!(&mut self.buffer, "cmd,pts=zip(*dat)\n").unwrap();
write!(&mut self.buffer, "h=pth.Path(pts,cmd)\n").unwrap();
write!(&mut self.buffer, "p=pat.PathPatch(h{})\n", &opt).unwrap();
write!(&mut self.buffer, "plt.gca().add_patch(p)\n").unwrap();
}
pub fn set_edge_color(&mut self, color: &str) -> &mut Self {
self.edge_color = String::from(color);
self
}
pub fn set_face_color(&mut self, color: &str) -> &mut Self {
self.face_color = String::from(color);
self
}
pub fn set_line_width(&mut self, width: f64) -> &mut Self {
self.line_width = width;
self
}
pub fn set_arrow_scale(&mut self, scale: f64) -> &mut Self {
self.arrow_scale = scale;
self
}
pub fn set_arrow_style(&mut self, style: &str) -> &mut Self {
self.arrow_style = String::from(style);
self
}
fn options_shared(&self) -> String {
let mut opt = String::new();
if self.edge_color != "" {
write!(&mut opt, ",edgecolor='{}'", self.edge_color).unwrap();
}
if self.face_color != "" {
write!(&mut opt, ",facecolor='{}'", self.face_color).unwrap();
}
if self.line_width > 0.0 {
write!(&mut opt, ",linewidth={}", self.line_width).unwrap();
}
opt
}
fn options_arrow(&self) -> String {
let mut opt = String::new();
if self.arrow_scale > 0.0 {
write!(&mut opt, ",mutation_scale={}", self.arrow_scale).unwrap();
}
if self.arrow_style != "" {
write!(&mut opt, ",arrowstyle='{}'", self.arrow_style).unwrap();
}
opt
}
}
impl GraphMaker for Shapes {
fn get_buffer<'a>(&'a self) -> &'a String {
&self.buffer
}
}
#[cfg(test)]
mod tests {
use super::Shapes;
#[test]
fn new_works() {
let shapes = Shapes::new();
assert_eq!(shapes.edge_color.len(), 0);
assert_eq!(shapes.face_color.len(), 0);
assert_eq!(shapes.line_width, 0.0);
assert_eq!(shapes.arrow_scale, 0.0);
assert_eq!(shapes.arrow_style.len(), 0);
assert_eq!(shapes.buffer.len(), 0);
}
#[test]
fn options_shared_works() {
let mut shapes = Shapes::new();
shapes.set_edge_color("red").set_face_color("blue").set_line_width(2.5);
let opt = shapes.options_shared();
assert_eq!(
opt,
",edgecolor='red'\
,facecolor='blue'\
,linewidth=2.5"
);
}
#[test]
fn options_arrow_works() {
let mut shapes = Shapes::new();
shapes.set_arrow_scale(25.0).set_arrow_style("fancy");
let opt = shapes.options_arrow();
assert_eq!(
opt,
",mutation_scale=25\
,arrowstyle='fancy'"
);
}
#[test]
fn arc_works() {
let mut shapes = Shapes::new();
shapes.draw_arc(0.0, 0.0, 1.0, 30.0, 60.0);
let b: &str = "p=pat.Arc((0,0),2*1,2*1,theta1=30,theta2=60,angle=0)\n\
plt.gca().add_patch(p)\n";
assert_eq!(shapes.buffer, b);
}
#[test]
fn arrow_woks() {
let mut shapes = Shapes::new();
shapes.draw_arrow(0.0, 0.0, 1.0, 1.0);
let b: &str =
"p=pat.FancyArrowPatch((0,0),(1,1),shrinkA=0,shrinkB=0,path_effects=[pff.Stroke(joinstyle='miter')])\n\
plt.gca().add_patch(p)\n";
assert_eq!(shapes.buffer, b);
}
#[test]
fn circle_works() {
let mut shapes = Shapes::new();
shapes.draw_circle(0.0, 0.0, 1.0);
let b: &str = "p=pat.Circle((0,0),1)\n\
plt.gca().add_patch(p)\n";
assert_eq!(shapes.buffer, b);
}
#[test]
fn polyline_works() {
let mut shapes = Shapes::new();
let points = vec![vec![1.0, 1.0], vec![2.0, 1.0], vec![1.5, 1.866]];
shapes.draw_polyline(&points, true);
let b: &str = "dat=[[pth.Path.MOVETO,(1,1)],[pth.Path.LINETO,(2,1)],[pth.Path.LINETO,(1.5,1.866)],[pth.Path.CLOSEPOLY,(None,None)]]\n\
cmd,pts=zip(*dat)\n\
h=pth.Path(pts,cmd)\n\
p=pat.PathPatch(h)\n\
plt.gca().add_patch(p)\n";
assert_eq!(shapes.buffer, b);
}
}