1use crate::basics::{
8 VertexSource, PATH_CMD_END_POLY, PATH_CMD_LINE_TO, PATH_CMD_MOVE_TO, PATH_CMD_STOP,
9 PATH_FLAGS_CCW, PATH_FLAGS_CLOSE,
10};
11
12pub struct Arrowhead {
19 head_d1: f64,
20 head_d2: f64,
21 head_d3: f64,
22 head_d4: f64,
23 tail_d1: f64,
24 tail_d2: f64,
25 tail_d3: f64,
26 tail_d4: f64,
27 head_flag: bool,
28 tail_flag: bool,
29 coord: [f64; 16],
30 cmd: [u32; 8],
31 curr_id: u32,
32 curr_coord: u32,
33}
34
35impl Arrowhead {
36 pub fn new() -> Self {
38 Self {
39 head_d1: 1.0,
40 head_d2: 1.0,
41 head_d3: 1.0,
42 head_d4: 0.0,
43 tail_d1: 1.0,
44 tail_d2: 1.0,
45 tail_d3: 1.0,
46 tail_d4: 0.0,
47 head_flag: false,
48 tail_flag: false,
49 coord: [0.0; 16],
50 cmd: [0; 8],
51 curr_id: 0,
52 curr_coord: 0,
53 }
54 }
55
56 pub fn head(&mut self, d1: f64, d2: f64, d3: f64, d4: f64) {
58 self.head_d1 = d1;
59 self.head_d2 = d2;
60 self.head_d3 = d3;
61 self.head_d4 = d4;
62 self.head_flag = true;
63 }
64
65 pub fn enable_head(&mut self) {
67 self.head_flag = true;
68 }
69
70 pub fn no_head(&mut self) {
72 self.head_flag = false;
73 }
74
75 pub fn tail(&mut self, d1: f64, d2: f64, d3: f64, d4: f64) {
77 self.tail_d1 = d1;
78 self.tail_d2 = d2;
79 self.tail_d3 = d3;
80 self.tail_d4 = d4;
81 self.tail_flag = true;
82 }
83
84 pub fn enable_tail(&mut self) {
86 self.tail_flag = true;
87 }
88
89 pub fn no_tail(&mut self) {
91 self.tail_flag = false;
92 }
93}
94
95impl Default for Arrowhead {
96 fn default() -> Self {
97 Self::new()
98 }
99}
100
101impl VertexSource for Arrowhead {
102 fn rewind(&mut self, path_id: u32) {
103 self.curr_id = path_id;
104 self.curr_coord = 0;
105
106 if path_id == 0 {
107 if !self.tail_flag {
108 self.cmd[0] = PATH_CMD_STOP;
109 return;
110 }
111 self.coord[0] = self.tail_d1;
112 self.coord[1] = 0.0;
113 self.coord[2] = self.tail_d1 - self.tail_d4;
114 self.coord[3] = self.tail_d3;
115 self.coord[4] = -self.tail_d2 - self.tail_d4;
116 self.coord[5] = self.tail_d3;
117 self.coord[6] = -self.tail_d2;
118 self.coord[7] = 0.0;
119 self.coord[8] = -self.tail_d2 - self.tail_d4;
120 self.coord[9] = -self.tail_d3;
121 self.coord[10] = self.tail_d1 - self.tail_d4;
122 self.coord[11] = -self.tail_d3;
123
124 self.cmd[0] = PATH_CMD_MOVE_TO;
125 self.cmd[1] = PATH_CMD_LINE_TO;
126 self.cmd[2] = PATH_CMD_LINE_TO;
127 self.cmd[3] = PATH_CMD_LINE_TO;
128 self.cmd[4] = PATH_CMD_LINE_TO;
129 self.cmd[5] = PATH_CMD_LINE_TO;
130 self.cmd[7] = PATH_CMD_END_POLY | PATH_FLAGS_CLOSE | PATH_FLAGS_CCW;
131 self.cmd[6] = PATH_CMD_STOP;
132 } else if path_id == 1 {
133 if !self.head_flag {
134 self.cmd[0] = PATH_CMD_STOP;
135 return;
136 }
137 self.coord[0] = -self.head_d1;
138 self.coord[1] = 0.0;
139 self.coord[2] = self.head_d2 + self.head_d4;
140 self.coord[3] = -self.head_d3;
141 self.coord[4] = self.head_d2;
142 self.coord[5] = 0.0;
143 self.coord[6] = self.head_d2 + self.head_d4;
144 self.coord[7] = self.head_d3;
145
146 self.cmd[0] = PATH_CMD_MOVE_TO;
147 self.cmd[1] = PATH_CMD_LINE_TO;
148 self.cmd[2] = PATH_CMD_LINE_TO;
149 self.cmd[3] = PATH_CMD_LINE_TO;
150 self.cmd[4] = PATH_CMD_END_POLY | PATH_FLAGS_CLOSE | PATH_FLAGS_CCW;
151 self.cmd[5] = PATH_CMD_STOP;
152 }
153 }
154
155 fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32 {
156 if self.curr_id < 2 {
157 let curr_idx = self.curr_coord as usize * 2;
158 *x = self.coord[curr_idx];
159 *y = self.coord[curr_idx + 1];
160 let cmd = self.cmd[self.curr_coord as usize];
161 self.curr_coord += 1;
162 return cmd;
163 }
164 PATH_CMD_STOP
165 }
166}
167
168#[cfg(test)]
173mod tests {
174 use super::*;
175 use crate::basics::{is_end_poly, is_stop};
176
177 #[test]
178 fn test_arrowhead_default() {
179 let ah = Arrowhead::new();
180 assert!(!ah.head_flag);
181 assert!(!ah.tail_flag);
182 }
183
184 #[test]
185 fn test_arrowhead_tail_disabled() {
186 let mut ah = Arrowhead::new();
187 ah.rewind(0);
188 let mut x = 0.0;
189 let mut y = 0.0;
190 let cmd = ah.vertex(&mut x, &mut y);
191 assert!(is_stop(cmd));
192 }
193
194 #[test]
195 fn test_arrowhead_head_disabled() {
196 let mut ah = Arrowhead::new();
197 ah.rewind(1);
198 let mut x = 0.0;
199 let mut y = 0.0;
200 let cmd = ah.vertex(&mut x, &mut y);
201 assert!(is_stop(cmd));
202 }
203
204 #[test]
205 fn test_arrowhead_tail_polygon() {
206 let mut ah = Arrowhead::new();
207 ah.tail(5.0, 5.0, 3.0, 1.0);
208 ah.rewind(0);
209 let mut x = 0.0;
210 let mut y = 0.0;
211
212 let cmd = ah.vertex(&mut x, &mut y);
214 assert_eq!(cmd, PATH_CMD_MOVE_TO);
215 assert!((x - 5.0).abs() < 1e-10); assert!(y.abs() < 1e-10);
217
218 for _ in 0..5 {
219 let cmd = ah.vertex(&mut x, &mut y);
220 assert_eq!(cmd, PATH_CMD_LINE_TO);
221 }
222
223 let cmd = ah.vertex(&mut x, &mut y);
225 assert!(is_stop(cmd));
226 }
227
228 #[test]
229 fn test_arrowhead_head_polygon() {
230 let mut ah = Arrowhead::new();
231 ah.head(5.0, 5.0, 3.0, 1.0);
232 ah.rewind(1);
233 let mut x = 0.0;
234 let mut y = 0.0;
235
236 let cmd = ah.vertex(&mut x, &mut y);
238 assert_eq!(cmd, PATH_CMD_MOVE_TO);
239 assert!((x + 5.0).abs() < 1e-10); for _ in 0..3 {
242 let cmd = ah.vertex(&mut x, &mut y);
243 assert_eq!(cmd, PATH_CMD_LINE_TO);
244 }
245
246 let cmd = ah.vertex(&mut x, &mut y);
248 assert!(is_end_poly(cmd));
249
250 let cmd = ah.vertex(&mut x, &mut y);
252 assert!(is_stop(cmd));
253 }
254
255 #[test]
256 fn test_arrowhead_invalid_path_id() {
257 let mut ah = Arrowhead::new();
258 ah.rewind(5); let mut x = 0.0;
260 let mut y = 0.0;
261 let cmd = ah.vertex(&mut x, &mut y);
262 assert!(is_stop(cmd));
263 }
264
265 #[test]
266 fn test_arrowhead_enable_disable() {
267 let mut ah = Arrowhead::new();
268 ah.head(5.0, 5.0, 3.0, 1.0);
269 assert!(ah.head_flag);
270
271 ah.no_head();
272 assert!(!ah.head_flag);
273
274 ah.enable_head();
275 assert!(ah.head_flag);
276
277 ah.tail(5.0, 5.0, 3.0, 1.0);
278 assert!(ah.tail_flag);
279
280 ah.no_tail();
281 assert!(!ah.tail_flag);
282
283 ah.enable_tail();
284 assert!(ah.tail_flag);
285 }
286
287 #[test]
288 fn test_arrowhead_tail_vertex_coords() {
289 let mut ah = Arrowhead::new();
290 ah.tail(5.0, 5.0, 3.0, 1.0);
291 ah.rewind(0);
292 let mut x = 0.0;
293 let mut y = 0.0;
294
295 ah.vertex(&mut x, &mut y);
297 assert!((x - 5.0).abs() < 1e-10);
298 assert!(y.abs() < 1e-10);
299
300 ah.vertex(&mut x, &mut y);
302 assert!((x - 4.0).abs() < 1e-10);
303 assert!((y - 3.0).abs() < 1e-10);
304
305 ah.vertex(&mut x, &mut y);
307 assert!((x + 6.0).abs() < 1e-10);
308 assert!((y - 3.0).abs() < 1e-10);
309
310 ah.vertex(&mut x, &mut y);
312 assert!((x + 5.0).abs() < 1e-10);
313 assert!(y.abs() < 1e-10);
314
315 ah.vertex(&mut x, &mut y);
317 assert!((x + 6.0).abs() < 1e-10);
318 assert!((y + 3.0).abs() < 1e-10);
319
320 ah.vertex(&mut x, &mut y);
322 assert!((x - 4.0).abs() < 1e-10);
323 assert!((y + 3.0).abs() < 1e-10);
324 }
325}