1use alloc::vec::Vec;
10
11use super::raster::Raster;
12use super::{Dc, Surface};
13use rt::fx::{maxss, sqrt};
14
15const KAPPA_FX: i32 = 141; #[derive(Clone, Copy)]
18pub(crate) struct Sub {
19 pub start: usize,
20 pub count: usize,
21 pub closed: bool,
22}
23
24#[derive(Default)]
25pub struct Path {
26 pub(crate) pts: Vec<(f32, f32)>,
27 pub(crate) subs: Vec<Sub>,
28 open: bool,
29 start: (f32, f32),
30 cur: (f32, f32),
31 ox: i32,
32 oy: i32,
33 tolerance: f32,
34}
35
36#[inline]
38pub(crate) fn zf(a: f32, b: f32) -> bool {
39 !(a < b || a > b)
40}
41
42fn seg_count(m: f32, k: f32) -> i32 {
44 let v = sqrt(m * k);
45 let mut n = rt::fx::cvtt(v);
46 if !((n as f32) >= v) {
47 n += 1;
48 }
49 n.clamp(1, 128)
50}
51
52fn vlen(x: f32, y: f32) -> f32 {
53 sqrt(x * x + y * y)
54}
55
56impl Path {
57 pub fn set_tolerance(&mut self, tolerance: f32) -> f32 {
60 let old = if self.tolerance > 0.0 { self.tolerance } else { 0.2 };
61 if tolerance.is_finite() && tolerance > 0.0 {
62 self.tolerance = tolerance.clamp(0.001, 10.0);
63 }
64 old
65 }
66
67 fn curve_factor(&self) -> f32 {
68 if self.tolerance > 0.0 { 0.2 / self.tolerance } else { 1.0 }
69 }
70 pub fn begin(&mut self, dc: &Dc) {
72 self.pts.clear();
73 self.subs.clear();
74 self.open = false;
75 self.ox = dc.ox;
76 self.oy = dc.oy;
77 }
78
79 pub fn reset(&mut self) {
81 self.pts.clear();
82 self.subs.clear();
83 self.open = false;
84 }
85
86 pub fn set_origin(&mut self, ox: i32, oy: i32) {
87 self.ox = ox;
88 self.oy = oy;
89 }
90
91 pub fn is_empty(&self) -> bool {
92 self.subs.is_empty()
93 }
94
95 pub fn pts_mut(&mut self) -> &mut [(f32, f32)] {
98 &mut self.pts
99 }
100
101 fn to_xy(&self, x: i32, y: i32) -> (f32, f32) {
102 (x as f32 * (1.0 / 256.0) + self.ox as f32, y as f32 * (1.0 / 256.0) + self.oy as f32)
103 }
104
105 fn new_sub(&mut self, p: (f32, f32)) {
106 self.subs.push(Sub { start: self.pts.len(), count: 0, closed: false });
107 self.open = true;
108 self.start = p;
109 }
110
111 pub fn add_pt(&mut self, p: (f32, f32)) {
114 if !self.open {
115 if !self.subs.is_empty() {
116 let c = self.cur;
117 self.new_sub(c);
118 self.add_pt(c);
119 } else {
120 self.new_sub(p);
121 }
122 }
123 let si = self.subs.len() - 1;
124 if self.subs[si].count != 0 {
125 let last = self.pts[self.pts.len() - 1];
126 if zf(p.0, last.0) && zf(p.1, last.1) {
127 return;
128 }
129 }
130 self.pts.push(p);
131 self.subs[si].count += 1;
132 self.cur = p;
133 }
134
135 pub fn move_fx(&mut self, x: i32, y: i32) {
136 let p = self.to_xy(x, y);
137 self.new_sub(p);
138 self.add_pt(p);
139 }
140
141 pub fn move_f(&mut self, x: f32, y: f32) {
142 self.new_sub((x, y));
143 self.add_pt((x, y));
144 }
145
146 pub fn line_fx(&mut self, x: i32, y: i32) {
147 let p = self.to_xy(x, y);
148 self.add_pt(p);
149 }
150
151 pub fn line_f(&mut self, x: f32, y: f32) {
152 self.add_pt((x, y));
153 }
154
155 pub fn close(&mut self) {
156 if self.open {
157 let si = self.subs.len() - 1;
158 self.subs[si].closed = true;
159 self.open = false;
160 self.cur = self.start;
161 }
162 }
163
164 pub fn quad_fx(&mut self, cx: i32, cy: i32, x: i32, y: i32) {
166 let c = self.to_xy(cx, cy);
167 let p = self.to_xy(x, y);
168 self.quad_f(c.0, c.1, p.0, p.1);
169 }
170
171 pub fn quad_f(&mut self, cx: f32, cy: f32, x: f32, y: f32) {
173 if self.subs.is_empty() {
174 self.new_sub((cx, cy));
175 self.add_pt((cx, cy));
176 }
177 let (p0x, p0y) = self.cur;
178 let mx = p0x - (cx + cx) + x;
179 let my = p0y - (cy + cy) + y;
180 let n = seg_count(vlen(mx, my), 1.25 * self.curve_factor());
181 for i in 1..=n {
182 let t = i as f32 / n as f32;
183 let u = 1.0 - t;
184 let b0 = u * u;
185 let mut b1 = t * u;
186 b1 = b1 + b1;
187 let b2 = t * t;
188 let mut px = p0x * b0 + cx * b1 + x * b2;
189 let mut py = p0y * b0 + cy * b1 + y * b2;
190 if i == n {
191 px = x;
192 py = y;
193 }
194 self.add_pt((px, py));
195 }
196 }
197
198 pub fn cubic_fx(&mut self, c1x: i32, c1y: i32, c2x: i32, c2y: i32, x: i32, y: i32) {
200 let p1 = self.to_xy(c1x, c1y);
201 let p2 = self.to_xy(c2x, c2y);
202 let p3 = self.to_xy(x, y);
203 self.cubic_f(p1, p2, p3);
204 }
205
206 pub fn cubic_f(&mut self, p1: (f32, f32), p2: (f32, f32), p3: (f32, f32)) {
208 if self.subs.is_empty() {
209 self.new_sub(p1);
210 self.add_pt(p1);
211 }
212 let p0 = self.cur;
213 let m1 = vlen(p0.0 - (p1.0 + p1.0) + p2.0, p0.1 - (p1.1 + p1.1) + p2.1);
214 let m2 = vlen(p1.0 - (p2.0 + p2.0) + p3.0, p1.1 - (p2.1 + p2.1) + p3.1);
215 let n = seg_count(maxss(m2, m1), 3.75 * self.curve_factor());
216 for i in 1..=n {
217 if i == n {
218 self.add_pt(p3);
219 break;
220 }
221 let t = i as f32 / n as f32;
222 let u = 1.0 - t;
223 let uu = u * u;
224 let b0 = uu * u;
225 let b1 = uu * t * 3.0;
226 let tt = t * t;
227 let b2 = tt * u * 3.0;
228 let b3 = tt * t;
229 let px = p0.0 * b0 + p1.0 * b1 + p2.0 * b2 + p3.0 * b3;
230 let py = p0.1 * b0 + p1.1 * b1 + p2.1 * b2 + p3.1 * b3;
231 self.add_pt((px, py));
232 }
233 }
234
235 pub fn rect_fx(&mut self, x: i32, y: i32, w: i32, h: i32) {
236 let x1 = x + w;
237 let y1 = y + h;
238 self.move_fx(x, y);
239 self.line_fx(x1, y);
240 self.line_fx(x1, y1);
241 self.line_fx(x, y1);
242 self.close();
243 }
244
245 pub fn rrect_fx(&mut self, x: i32, y: i32, w: i32, h: i32, r: i32) {
247 let (x0, y0, x1, y1) = (x, y, x + w, y + h);
248 let r = r.min(w.min(h) >> 1);
249 if r <= 0 {
250 self.rect_fx(x, y, w, y1 - y0);
251 return;
252 }
253 let k = (r * (256 - KAPPA_FX)) >> 8;
254 self.move_fx(x0 + r, y0);
255 self.line_fx(x1 - r, y0);
256 self.cubic_fx(x1 - k, y0, x1, y0 + k, x1, y0 + r);
257 self.line_fx(x1, y1 - r);
258 self.cubic_fx(x1, y1 - k, x1 - k, y1, x1 - r, y1);
259 self.line_fx(x0 + r, y1);
260 self.cubic_fx(x0 + k, y1, x0, y1 - k, x0, y1 - r);
261 self.line_fx(x0, y0 + r);
262 self.cubic_fx(x0, y0 + k, x0 + k, y0, x0 + r, y0);
263 self.close();
264 }
265
266 pub fn ellipse_fx(&mut self, cx: i32, cy: i32, rx: i32, ry: i32) {
268 let kx = (rx * KAPPA_FX) >> 8;
269 let ky = (ry * KAPPA_FX) >> 8;
270 self.move_fx(cx + rx, cy);
271 self.cubic_fx(cx + rx, cy + ky, cx + kx, cy + ry, cx, cy + ry);
272 self.cubic_fx(cx - kx, cy + ry, cx - rx, cy + ky, cx - rx, cy);
273 self.cubic_fx(cx - rx, cy - ky, cx - kx, cy - ry, cx, cy - ry);
274 self.cubic_fx(cx + kx, cy - ry, cx + rx, cy - ky, cx + rx, cy);
275 self.close();
276 }
277
278 pub fn fill_lines(&self, ras: &mut Raster) {
280 ras.lines_begin();
281 for s in &self.subs {
282 if s.count < 2 {
283 continue;
284 }
285 for k in 0..s.count {
286 let a = self.pts[s.start + k];
287 let b = if k + 1 < s.count { self.pts[s.start + k + 1] } else { self.pts[s.start] };
288 ras.emit_line(a.0, a.1, b.0, b.1);
289 }
290 }
291 }
292
293 pub fn fill(&self, ras: &mut Raster, dc: &Dc, sf: &mut Surface, rule: u32) {
295 self.fill_lines(ras);
296 ras.fill(dc, sf, rule);
297 }
298}