1extern crate svg;
15
16use std::process;
17use std::collections::HashSet;
18
19use svg::node::element::path::Data;
20use svg::node::element::Path;
21use svg::Document;
22
23pub fn recaman_sequence(n: u32) -> Vec<u32> {
24 if n == 0 {
25 return vec![];
26 }
27
28 let mut used_numbers = HashSet::new();
29 let mut seq: Vec<u32> = vec![0];
30 while seq.len() < n as usize {
31 let seq_len = seq.len() as i32;
32 let last = *seq.last().unwrap() as i32;
33 let subtract_result = last - seq_len;
34
35 let a: i32;
36 if subtract_result > 0 && !used_numbers.contains(&(subtract_result as u32)) {
37 a = subtract_result;
38 } else {
39 a = last + seq_len;
40 }
41
42 seq.push(a as u32);
43 used_numbers.insert(a as u32);
44 }
45
46 seq
47}
48
49fn get_line_height(recaman_sequence: &Vec<u32>) -> f32 {
56 0.5 * recaman_sequence.len() as f32
57}
58
59pub fn generate_svg_document(recaman_sequence: &Vec<u32>, stroke_width: f32) -> svg::Document {
60 const ARC_LARGE_FLAG: u32 = 0;
61 const ARC_ANGLE: u32 = 0;
62 const ARC_RX: u32 = 1;
63 const ARC_RY: u32 = 1;
64 const X_SCALE: u32 = 2;
65
66 let scale = |x: f32| x * X_SCALE as f32;
67 let line_height = scale(get_line_height(recaman_sequence));
68
69 let mut data = Data::new().move_to((0, line_height));
70 let mut should_go_up = false;
71 let mut last_x = 0;
72 let mut max_x = u32::min_value();
73 for x in recaman_sequence {
74 let x = *x;
75 let sweep_flag = if x > last_x {
76 !should_go_up
77 } else {
78 should_go_up
80 };
81
82 data = data.elliptical_arc_to((
83 ARC_RX,
84 ARC_RY,
85 ARC_ANGLE,
86 ARC_LARGE_FLAG,
87 sweep_flag as u32,
88 scale(x as f32),
89 line_height,
90 ));
91
92 last_x = x;
93 should_go_up = !should_go_up;
94 max_x = max_x.max(x);
95 }
96
97 const MARGIN: f32 = 2.0;
98 let document = Document::new().set(
99 "viewBox",
100 (
101 scale(0.0 - MARGIN),
102 scale(0.0 - MARGIN),
103 scale(max_x as f32 + MARGIN * 2.0),
104 line_height * 2.0 + scale(MARGIN * 2.0),
105 ),
106 );
107 let path = Path::new()
108 .set("fill", "none")
109 .set("stroke", "black")
110 .set("stroke-width", stroke_width)
111 .set("d", data);
112
113 document.add(path)
114}
115
116pub fn write_svg_document(document: svg::Document, filename: &str) {
117 svg::save(filename, &document).unwrap_or_else(|err| {
118 eprintln!("Couldn't write file: {}", err.to_string().to_lowercase());
119 process::exit(1);
120 });
121}