1use super::{commands::draw::Draw, point::Point, ArrowType, ExtendPath, PathCommand};
2
3pub struct Line<T>
4where
5 T: ExtendPath,
6{
7 parent: T,
8 x: String,
9 y: String,
10 thick: bool,
11 start: ArrowType,
12 end: ArrowType,
13}
14
15impl<T> Line<T>
16where
17 T: ExtendPath,
18{
19 fn new(
20 parent: T,
21 x: impl num::Num + std::fmt::Display,
22 y: impl num::Num + std::fmt::Display,
23 ) -> Self {
24 Line {
25 parent,
26 x: x.to_string(),
27 y: y.to_string(),
28 thick: false,
29 start: ArrowType::Default,
30 end: ArrowType::Default,
31 }
32 }
33
34 pub fn start(mut self, start: ArrowType) -> Self {
35 self.start = start;
36 self
37 }
38
39 pub fn end(mut self, end: ArrowType) -> Self {
40 self.end = end;
41 self
42 }
43
44 pub fn thick(mut self, thick: bool) -> Self {
45 self.thick = thick;
46 self
47 }
48
49 fn options(&self) -> String {
50 let mut options = Vec::new();
51 if self.thick {
52 options.push("thick".into());
53 }
54
55 match (&self.start, &self.end) {
56 (ArrowType::Default, ArrowType::Default) => {}
57 (start, end) => options.push(format!("{}-{}", start, end)),
58 };
59
60 if options.is_empty() {
61 "".into()
62 } else {
63 format!(" [{}]", options.join(","))
64 }
65 }
66}
67
68impl<T> ExtendPath for Line<T> where T: ExtendPath {}
69
70impl<T> PathCommand for Line<T>
71where
72 T: ExtendPath,
73{
74 fn text(&self) -> String {
75 format!(
76 "{}{} -- ({}, {})",
77 self.parent.text(),
78 self.options(),
79 self.x,
80 self.y
81 )
82 }
83}
84
85impl<T> Draw<T>
86where
87 T: ExtendPath,
88{
89 pub fn extend_line(
90 self,
91 x: impl num::Num + std::fmt::Display,
92 y: impl num::Num + std::fmt::Display,
93 ) -> Draw<Line<T>> {
94 Draw {
95 current: Line::new(self.current, x, y),
96 }
97 }
98}
99
100impl<T> Draw<T>
101where
102 T: PathCommand,
103{
104 pub fn line(
105 self,
106 x1: impl num::Num + std::fmt::Display,
107 y1: impl num::Num + std::fmt::Display,
108 x2: impl num::Num + std::fmt::Display,
109 y2: impl num::Num + std::fmt::Display,
110 ) -> Draw<Line<Point<T>>> {
111 self.point(x1, y1).extend_line(x2, y2)
112 }
113}
114
115impl<T> Draw<Line<T>>
116where
117 T: ExtendPath,
118{
119 pub fn arrow_start(mut self, style: ArrowType) -> Self {
120 self.current = self.current.start(style);
121 self
122 }
123
124 pub fn arrow_end(mut self, style: ArrowType) -> Self {
125 self.current = self.current.end(style);
126 self
127 }
128
129 pub fn thick(mut self, thick: bool) -> Self {
130 self.current = self.current.thick(thick);
131 self
132 }
133}
134
135#[cfg(test)]
136#[test]
137fn does_it_work() {
138 use super::TikzPicture;
139
140 let no_options = TikzPicture::begin()
141 .and(Draw::new().point(0, 0).extend_line(1, 1))
142 .end();
143
144 let thick = TikzPicture::begin()
145 .and(Draw::new().point(0, 0).extend_line(1, 1).thick(true))
146 .end();
147
148 let styled_arrow = TikzPicture::begin()
149 .and(
150 Draw::new()
151 .point(0, 0)
152 .extend_line(1, 1)
153 .arrow_start(ArrowType::Stealth),
154 )
155 .end();
156
157 let multiple_options = TikzPicture::begin()
158 .and(
159 Draw::new()
160 .line(0, 0, 1, 1)
161 .arrow_start(ArrowType::Stealth)
162 .arrow_end(ArrowType::Stealth)
163 .thick(true),
164 )
165 .end();
166
167 assert_eq!(
168 no_options,
169 "\\begin{tikzpicture}\n\t\\draw (0, 0) -- (1, 1);\n\\end{tikzpicture}"
170 );
171 assert_eq!(
172 thick,
173 "\\begin{tikzpicture}\n\t\\draw (0, 0) [thick] -- (1, 1);\n\\end{tikzpicture}"
174 );
175 assert_eq!(
176 styled_arrow,
177 "\\begin{tikzpicture}\n\t\\draw (0, 0) [stealth-] -- (1, 1);\n\\end{tikzpicture}"
178 );
179 assert_eq!(
180 multiple_options,
181 "\\begin{tikzpicture}\n\t\\draw (0, 0) [thick,stealth-stealth] -- (1, 1);\n\\end{tikzpicture}");
182}