Skip to main content

agg_rust/
vcgen_smooth_poly1.rs

1//! Smooth polygon vertex generator.
2//!
3//! Port of `agg_vcgen_smooth_poly1.h` / `agg_vcgen_smooth_poly1.cpp`.
4
5use crate::array::{VertexDist, VertexSequence};
6use crate::basics::{
7    get_close_flag, is_move_to, is_stop, is_vertex, PATH_CMD_CURVE3, PATH_CMD_CURVE4,
8    PATH_CMD_END_POLY, PATH_CMD_LINE_TO, PATH_CMD_MOVE_TO, PATH_CMD_STOP,
9};
10use crate::conv_adaptor_vcgen::VcgenGenerator;
11
12#[derive(Debug, Clone, Copy, PartialEq)]
13enum Status {
14    Initial,
15    Ready,
16    Polygon,
17    CtrlB,
18    CtrlE,
19    Ctrl1,
20    Ctrl2,
21    EndPoly,
22    Stop,
23}
24
25/// Port of C++ `vcgen_smooth_poly1`.
26pub struct VcgenSmoothPoly1 {
27    src_vertices: VertexSequence,
28    smooth_value: f64,
29    closed: u32,
30    status: Status,
31    src_vertex: usize,
32    ctrl1_x: f64,
33    ctrl1_y: f64,
34    ctrl2_x: f64,
35    ctrl2_y: f64,
36}
37
38impl VcgenSmoothPoly1 {
39    pub fn new() -> Self {
40        Self {
41            src_vertices: VertexSequence::new(),
42            smooth_value: 0.5,
43            closed: 0,
44            status: Status::Initial,
45            src_vertex: 0,
46            ctrl1_x: 0.0,
47            ctrl1_y: 0.0,
48            ctrl2_x: 0.0,
49            ctrl2_y: 0.0,
50        }
51    }
52
53    pub fn set_smooth_value(&mut self, v: f64) {
54        self.smooth_value = v * 0.5;
55    }
56
57    pub fn smooth_value(&self) -> f64 {
58        self.smooth_value * 2.0
59    }
60
61    pub fn remove_all(&mut self) {
62        self.src_vertices.remove_all();
63        self.closed = 0;
64        self.status = Status::Initial;
65    }
66
67    pub fn add_vertex(&mut self, x: f64, y: f64, cmd: u32) {
68        self.status = Status::Initial;
69        if is_move_to(cmd) {
70            self.src_vertices.modify_last(VertexDist::new(x, y));
71        } else if is_vertex(cmd) {
72            self.src_vertices.add(VertexDist::new(x, y));
73        } else {
74            self.closed = get_close_flag(cmd);
75        }
76    }
77
78    pub fn rewind(&mut self, _path_id: u32) {
79        if self.status == Status::Initial {
80            self.src_vertices.close(self.closed != 0);
81        }
82        self.status = Status::Ready;
83        self.src_vertex = 0;
84    }
85
86    fn calculate(&mut self, v0: &VertexDist, v1: &VertexDist, v2: &VertexDist, v3: &VertexDist) {
87        let k1 = v0.dist / (v0.dist + v1.dist);
88        let k2 = v1.dist / (v1.dist + v2.dist);
89
90        let xm1 = v0.x + (v2.x - v0.x) * k1;
91        let ym1 = v0.y + (v2.y - v0.y) * k1;
92        let xm2 = v1.x + (v3.x - v1.x) * k2;
93        let ym2 = v1.y + (v3.y - v1.y) * k2;
94
95        self.ctrl1_x = v1.x + self.smooth_value * (v2.x - xm1);
96        self.ctrl1_y = v1.y + self.smooth_value * (v2.y - ym1);
97        self.ctrl2_x = v2.x + self.smooth_value * (v1.x - xm2);
98        self.ctrl2_y = v2.y + self.smooth_value * (v1.y - ym2);
99    }
100
101    pub fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32 {
102        let mut cmd = PATH_CMD_LINE_TO;
103        loop {
104            if is_stop(cmd) {
105                return cmd;
106            }
107            match self.status {
108                Status::Initial => {
109                    self.rewind(0);
110                    continue;
111                }
112                Status::Ready => {
113                    if self.src_vertices.size() < 2 {
114                        cmd = PATH_CMD_STOP;
115                        continue;
116                    }
117                    if self.src_vertices.size() == 2 {
118                        *x = self.src_vertices[self.src_vertex].x;
119                        *y = self.src_vertices[self.src_vertex].y;
120                        self.src_vertex += 1;
121                        if self.src_vertex == 1 {
122                            return PATH_CMD_MOVE_TO;
123                        }
124                        if self.src_vertex == 2 {
125                            return PATH_CMD_LINE_TO;
126                        }
127                        cmd = PATH_CMD_STOP;
128                        continue;
129                    }
130                    cmd = PATH_CMD_MOVE_TO;
131                    self.status = Status::Polygon;
132                    self.src_vertex = 0;
133                    continue;
134                }
135                Status::Polygon => {
136                    if self.closed != 0 {
137                        if self.src_vertex >= self.src_vertices.size() {
138                            *x = self.src_vertices[0].x;
139                            *y = self.src_vertices[0].y;
140                            self.status = Status::EndPoly;
141                            return PATH_CMD_CURVE4;
142                        }
143                    } else if self.src_vertex >= self.src_vertices.size() - 1 {
144                        *x = self.src_vertices[self.src_vertices.size() - 1].x;
145                        *y = self.src_vertices[self.src_vertices.size() - 1].y;
146                        self.status = Status::EndPoly;
147                        return PATH_CMD_CURVE3;
148                    }
149
150                    let v0 = *self.src_vertices.prev(self.src_vertex);
151                    let v1 = *self.src_vertices.curr(self.src_vertex);
152                    let v2 = *self.src_vertices.next(self.src_vertex);
153                    let v3 = *self.src_vertices.next(self.src_vertex + 1);
154                    self.calculate(&v0, &v1, &v2, &v3);
155
156                    *x = self.src_vertices[self.src_vertex].x;
157                    *y = self.src_vertices[self.src_vertex].y;
158                    self.src_vertex += 1;
159
160                    if self.closed != 0 {
161                        self.status = Status::Ctrl1;
162                        return if self.src_vertex == 1 {
163                            PATH_CMD_MOVE_TO
164                        } else {
165                            PATH_CMD_CURVE4
166                        };
167                    }
168                    if self.src_vertex == 1 {
169                        self.status = Status::CtrlB;
170                        return PATH_CMD_MOVE_TO;
171                    }
172                    if self.src_vertex >= self.src_vertices.size() - 1 {
173                        self.status = Status::CtrlE;
174                        return PATH_CMD_CURVE3;
175                    }
176                    self.status = Status::Ctrl1;
177                    return PATH_CMD_CURVE4;
178                }
179                Status::CtrlB => {
180                    *x = self.ctrl2_x;
181                    *y = self.ctrl2_y;
182                    self.status = Status::Polygon;
183                    return PATH_CMD_CURVE3;
184                }
185                Status::CtrlE => {
186                    *x = self.ctrl1_x;
187                    *y = self.ctrl1_y;
188                    self.status = Status::Polygon;
189                    return PATH_CMD_CURVE3;
190                }
191                Status::Ctrl1 => {
192                    *x = self.ctrl1_x;
193                    *y = self.ctrl1_y;
194                    self.status = Status::Ctrl2;
195                    return PATH_CMD_CURVE4;
196                }
197                Status::Ctrl2 => {
198                    *x = self.ctrl2_x;
199                    *y = self.ctrl2_y;
200                    self.status = Status::Polygon;
201                    return PATH_CMD_CURVE4;
202                }
203                Status::EndPoly => {
204                    self.status = Status::Stop;
205                    return PATH_CMD_END_POLY | self.closed;
206                }
207                Status::Stop => {
208                    return PATH_CMD_STOP;
209                }
210            }
211        }
212    }
213}
214
215impl Default for VcgenSmoothPoly1 {
216    fn default() -> Self {
217        Self::new()
218    }
219}
220
221impl VcgenGenerator for VcgenSmoothPoly1 {
222    fn remove_all(&mut self) {
223        self.remove_all();
224    }
225    fn add_vertex(&mut self, x: f64, y: f64, cmd: u32) {
226        self.add_vertex(x, y, cmd);
227    }
228    fn rewind(&mut self, path_id: u32) {
229        self.rewind(path_id);
230    }
231    fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32 {
232        self.vertex(x, y)
233    }
234}