1use crate::basics::VertexSource;
7use crate::conv_adaptor_vcgen::ConvAdaptorVcgen;
8use crate::vcgen_dash::VcgenDash;
9
10pub struct ConvDash<VS: VertexSource> {
18 base: ConvAdaptorVcgen<VS, VcgenDash>,
19}
20
21impl<VS: VertexSource> ConvDash<VS> {
22 pub fn new(source: VS) -> Self {
23 Self {
24 base: ConvAdaptorVcgen::new(source, VcgenDash::new()),
25 }
26 }
27
28 pub fn remove_all_dashes(&mut self) {
29 self.base.generator_mut().remove_all_dashes();
30 }
31
32 pub fn add_dash(&mut self, dash_len: f64, gap_len: f64) {
33 self.base.generator_mut().add_dash(dash_len, gap_len);
34 }
35
36 pub fn dash_start(&mut self, ds: f64) {
37 self.base.generator_mut().dash_start(ds);
38 }
39
40 pub fn set_shorten(&mut self, s: f64) {
41 self.base.generator_mut().set_shorten(s);
42 }
43 pub fn shorten(&self) -> f64 {
44 self.base.generator().shorten()
45 }
46
47 pub fn source(&self) -> &VS {
48 self.base.source()
49 }
50
51 pub fn source_mut(&mut self) -> &mut VS {
52 self.base.source_mut()
53 }
54}
55
56impl<VS: VertexSource> VertexSource for ConvDash<VS> {
57 fn rewind(&mut self, path_id: u32) {
58 self.base.rewind(path_id);
59 }
60
61 fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32 {
62 self.base.vertex(x, y)
63 }
64}
65
66#[cfg(test)]
71mod tests {
72 use super::*;
73 use crate::basics::{is_stop, PATH_CMD_LINE_TO, PATH_CMD_MOVE_TO};
74 use crate::path_storage::PathStorage;
75
76 fn collect_vertices<VS: VertexSource>(vs: &mut VS) -> Vec<(f64, f64, u32)> {
77 let mut result = Vec::new();
78 vs.rewind(0);
79 loop {
80 let (mut x, mut y) = (0.0, 0.0);
81 let cmd = vs.vertex(&mut x, &mut y);
82 if is_stop(cmd) {
83 break;
84 }
85 result.push((x, y, cmd));
86 }
87 result
88 }
89
90 #[test]
91 fn test_dash_empty_path() {
92 let path = PathStorage::new();
93 let mut dash = ConvDash::new(path);
94 dash.add_dash(10.0, 5.0);
95 let verts = collect_vertices(&mut dash);
96 assert!(verts.is_empty());
97 }
98
99 #[test]
100 fn test_dash_basic_pattern() {
101 let mut path = PathStorage::new();
102 path.move_to(0.0, 0.0);
103 path.line_to(100.0, 0.0);
104
105 let mut dash = ConvDash::new(path);
106 dash.add_dash(20.0, 10.0);
107 let verts = collect_vertices(&mut dash);
108
109 assert!(!verts.is_empty(), "Should produce dash vertices");
110 assert_eq!(verts[0].2, PATH_CMD_MOVE_TO);
111 }
112
113 #[test]
114 fn test_dash_has_gaps() {
115 let mut path = PathStorage::new();
116 path.move_to(0.0, 0.0);
117 path.line_to(100.0, 0.0);
118
119 let mut dash = ConvDash::new(path);
120 dash.add_dash(20.0, 10.0);
121 let verts = collect_vertices(&mut dash);
122
123 let move_count = verts.iter().filter(|v| v.2 == PATH_CMD_MOVE_TO).count();
124 assert!(
125 move_count >= 2,
126 "Expected multiple dash segments, got {} move_to",
127 move_count
128 );
129 }
130
131 #[test]
132 fn test_dash_no_pattern_no_output() {
133 let mut path = PathStorage::new();
134 path.move_to(0.0, 0.0);
135 path.line_to(100.0, 0.0);
136
137 let mut dash = ConvDash::new(path);
138 let verts = collect_vertices(&mut dash);
140 assert!(verts.is_empty());
141 }
142
143 #[test]
144 fn test_dash_rewind_replay() {
145 let mut path = PathStorage::new();
146 path.move_to(0.0, 0.0);
147 path.line_to(100.0, 0.0);
148
149 let mut dash = ConvDash::new(path);
150 dash.add_dash(15.0, 5.0);
151 let v1 = collect_vertices(&mut dash);
152 let v2 = collect_vertices(&mut dash);
153 assert_eq!(v1.len(), v2.len());
154 }
155
156 #[test]
157 fn test_dash_line_count() {
158 let mut path = PathStorage::new();
159 path.move_to(0.0, 0.0);
160 path.line_to(100.0, 0.0);
161
162 let mut dash = ConvDash::new(path);
163 dash.add_dash(20.0, 10.0);
164 let verts = collect_vertices(&mut dash);
165
166 let line_count = verts.iter().filter(|v| v.2 == PATH_CMD_LINE_TO).count();
167 assert!(
168 line_count >= 3,
169 "Expected multiple line segments, got {}",
170 line_count
171 );
172 }
173}