agg_rust/
bounding_rect.rs1use crate::basics::{is_stop, is_vertex, RectD, VertexSource};
7
8pub fn bounding_rect_single(vs: &mut dyn VertexSource, path_id: u32) -> Option<RectD> {
16 let mut x = 0.0;
17 let mut y = 0.0;
18 let mut first = true;
19 let mut x1 = 1.0_f64;
20 let mut y1 = 1.0_f64;
21 let mut x2 = 0.0_f64;
22 let mut y2 = 0.0_f64;
23
24 vs.rewind(path_id);
25 loop {
26 let cmd = vs.vertex(&mut x, &mut y);
27 if is_stop(cmd) {
28 break;
29 }
30 if is_vertex(cmd) {
31 if first {
32 x1 = x;
33 y1 = y;
34 x2 = x;
35 y2 = y;
36 first = false;
37 } else {
38 if x < x1 {
39 x1 = x;
40 }
41 if y < y1 {
42 y1 = y;
43 }
44 if x > x2 {
45 x2 = x;
46 }
47 if y > y2 {
48 y2 = y;
49 }
50 }
51 }
52 }
53
54 if x1 <= x2 && y1 <= y2 {
55 Some(RectD::new(x1, y1, x2, y2))
56 } else {
57 None
58 }
59}
60
61pub fn bounding_rect(
69 vs: &mut dyn VertexSource,
70 path_ids: &[u32],
71 start: usize,
72 num: usize,
73) -> Option<RectD> {
74 let mut x = 0.0;
75 let mut y = 0.0;
76 let mut first = true;
77 let mut x1 = 1.0_f64;
78 let mut y1 = 1.0_f64;
79 let mut x2 = 0.0_f64;
80 let mut y2 = 0.0_f64;
81
82 for i in 0..num {
83 vs.rewind(path_ids[start + i]);
84 loop {
85 let cmd = vs.vertex(&mut x, &mut y);
86 if is_stop(cmd) {
87 break;
88 }
89 if is_vertex(cmd) {
90 if first {
91 x1 = x;
92 y1 = y;
93 x2 = x;
94 y2 = y;
95 first = false;
96 } else {
97 if x < x1 {
98 x1 = x;
99 }
100 if y < y1 {
101 y1 = y;
102 }
103 if x > x2 {
104 x2 = x;
105 }
106 if y > y2 {
107 y2 = y;
108 }
109 }
110 }
111 }
112 }
113
114 if x1 <= x2 && y1 <= y2 {
115 Some(RectD::new(x1, y1, x2, y2))
116 } else {
117 None
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124 use crate::basics::{PATH_CMD_LINE_TO, PATH_CMD_MOVE_TO, PATH_CMD_STOP};
125 use crate::ellipse::Ellipse;
126
127 struct Triangle {
129 vertices: [(f64, f64); 3],
130 index: usize,
131 }
132
133 impl Triangle {
134 fn new(x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64) -> Self {
135 Self {
136 vertices: [(x1, y1), (x2, y2), (x3, y3)],
137 index: 0,
138 }
139 }
140 }
141
142 impl VertexSource for Triangle {
143 fn rewind(&mut self, _path_id: u32) {
144 self.index = 0;
145 }
146
147 fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32 {
148 if self.index < 3 {
149 *x = self.vertices[self.index].0;
150 *y = self.vertices[self.index].1;
151 self.index += 1;
152 if self.index == 1 {
153 PATH_CMD_MOVE_TO
154 } else {
155 PATH_CMD_LINE_TO
156 }
157 } else {
158 PATH_CMD_STOP
159 }
160 }
161 }
162
163 #[test]
164 fn test_bounding_rect_single_triangle() {
165 let mut tri = Triangle::new(10.0, 20.0, 50.0, 80.0, 30.0, 10.0);
166 let r = bounding_rect_single(&mut tri, 0).unwrap();
167 assert!((r.x1 - 10.0).abs() < 1e-10);
168 assert!((r.y1 - 10.0).abs() < 1e-10);
169 assert!((r.x2 - 50.0).abs() < 1e-10);
170 assert!((r.y2 - 80.0).abs() < 1e-10);
171 }
172
173 #[test]
174 fn test_bounding_rect_single_ellipse() {
175 let mut e = Ellipse::new(50.0, 50.0, 30.0, 20.0, 64, false);
176 let r = bounding_rect_single(&mut e, 0).unwrap();
177 assert!((r.x1 - 20.0).abs() < 1.0); assert!((r.y1 - 30.0).abs() < 1.0); assert!((r.x2 - 80.0).abs() < 1.0); assert!((r.y2 - 70.0).abs() < 1.0); }
183
184 #[test]
185 fn test_bounding_rect_empty_returns_none() {
186 struct Empty;
187 impl VertexSource for Empty {
188 fn rewind(&mut self, _: u32) {}
189 fn vertex(&mut self, _x: &mut f64, _y: &mut f64) -> u32 {
190 PATH_CMD_STOP
191 }
192 }
193 let mut e = Empty;
194 assert!(bounding_rect_single(&mut e, 0).is_none());
195 }
196
197 #[test]
198 fn test_bounding_rect_single_point() {
199 struct SinglePoint;
200 impl VertexSource for SinglePoint {
201 fn rewind(&mut self, _: u32) {}
202 fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32 {
203 static mut CALLED: bool = false;
205 unsafe {
206 if !CALLED {
207 CALLED = true;
208 *x = 42.0;
209 *y = 17.0;
210 PATH_CMD_MOVE_TO
211 } else {
212 CALLED = false; PATH_CMD_STOP
214 }
215 }
216 }
217 }
218 let mut sp = SinglePoint;
219 let r = bounding_rect_single(&mut sp, 0).unwrap();
220 assert!((r.x1 - 42.0).abs() < 1e-10);
221 assert!((r.y1 - 17.0).abs() < 1e-10);
222 assert!((r.x2 - 42.0).abs() < 1e-10);
223 assert!((r.y2 - 17.0).abs() < 1e-10);
224 }
225
226 #[test]
227 fn test_bounding_rect_multi_path() {
228 let mut tri = Triangle::new(10.0, 20.0, 50.0, 80.0, 30.0, 10.0);
229 let ids = [0u32];
230 let r = bounding_rect(&mut tri, &ids, 0, 1).unwrap();
231 assert!((r.x1 - 10.0).abs() < 1e-10);
232 assert!((r.y1 - 10.0).abs() < 1e-10);
233 assert!((r.x2 - 50.0).abs() < 1e-10);
234 assert!((r.y2 - 80.0).abs() < 1e-10);
235 }
236}