1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
9 //
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 //          mcseemagg@yahoo.com
13 //          http://www.antigrain.com
14 //----------------------------------------------------------------------------
15 //
16 // Stroke generator
17 //
18 //----------------------------------------------------------------------------
19 #include <math.h>
20 #include "agg_vcgen_stroke.h"
21 #include "agg_shorten_path.h"
22 
23 namespace agg
24 {
25 
26     //------------------------------------------------------------------------
vcgen_stroke()27     vcgen_stroke::vcgen_stroke() :
28         m_stroker(),
29         m_src_vertices(),
30         m_out_vertices(),
31         m_shorten(0.0),
32         m_closed(0),
33         m_status(initial),
34         m_src_vertex(0),
35         m_out_vertex(0)
36     {
37     }
38 
39     //------------------------------------------------------------------------
remove_all()40     void vcgen_stroke::remove_all()
41     {
42         m_src_vertices.remove_all();
43         m_closed = 0;
44         m_status = initial;
45     }
46 
47 
48     //------------------------------------------------------------------------
add_vertex(double x,double y,unsigned cmd)49     void vcgen_stroke::add_vertex(double x, double y, unsigned cmd)
50     {
51         m_status = initial;
52         if(is_move_to(cmd))
53         {
54             m_src_vertices.modify_last(vertex_dist(x, y));
55         }
56         else
57         {
58             if(is_vertex(cmd))
59             {
60                 m_src_vertices.add(vertex_dist(x, y));
61             }
62             else
63             {
64                 m_closed = get_close_flag(cmd);
65             }
66         }
67     }
68 
69     //------------------------------------------------------------------------
rewind(unsigned)70     void vcgen_stroke::rewind(unsigned)
71     {
72         if(m_status == initial)
73         {
74             m_src_vertices.close(m_closed != 0);
75             shorten_path(m_src_vertices, m_shorten, m_closed);
76             if(m_src_vertices.size() < 3) m_closed = 0;
77         }
78         m_status = ready;
79         m_src_vertex = 0;
80         m_out_vertex = 0;
81     }
82 
83 
84     //------------------------------------------------------------------------
vertex(double * x,double * y)85     unsigned vcgen_stroke::vertex(double* x, double* y)
86     {
87         unsigned cmd = path_cmd_line_to;
88         while(!is_stop(cmd))
89         {
90             switch(m_status)
91             {
92             case initial:
93                 rewind(0);
94 
95             case ready:
96                 if(m_src_vertices.size() < 2 + unsigned(m_closed != 0))
97                 {
98                     cmd = path_cmd_stop;
99                     break;
100                 }
101                 m_status = m_closed ? outline1 : cap1;
102                 cmd = path_cmd_move_to;
103                 m_src_vertex = 0;
104                 m_out_vertex = 0;
105                 break;
106 
107             case cap1:
108                 m_stroker.calc_cap(m_out_vertices,
109                                    m_src_vertices[0],
110                                    m_src_vertices[1],
111                                    m_src_vertices[0].dist);
112                 m_src_vertex = 1;
113                 m_prev_status = outline1;
114                 m_status = out_vertices;
115                 m_out_vertex = 0;
116                 break;
117 
118             case cap2:
119                 m_stroker.calc_cap(m_out_vertices,
120                                    m_src_vertices[m_src_vertices.size() - 1],
121                                    m_src_vertices[m_src_vertices.size() - 2],
122                                    m_src_vertices[m_src_vertices.size() - 2].dist);
123                 m_prev_status = outline2;
124                 m_status = out_vertices;
125                 m_out_vertex = 0;
126                 break;
127 
128             case outline1:
129                 if(m_closed)
130                 {
131                     if(m_src_vertex >= m_src_vertices.size())
132                     {
133                         m_prev_status = close_first;
134                         m_status = end_poly1;
135                         break;
136                     }
137                 }
138                 else
139                 {
140                     if(m_src_vertex >= m_src_vertices.size() - 1)
141                     {
142                         m_status = cap2;
143                         break;
144                     }
145                 }
146                 m_stroker.calc_join(m_out_vertices,
147                                     m_src_vertices.prev(m_src_vertex),
148                                     m_src_vertices.curr(m_src_vertex),
149                                     m_src_vertices.next(m_src_vertex),
150                                     m_src_vertices.prev(m_src_vertex).dist,
151                                     m_src_vertices.curr(m_src_vertex).dist);
152                 ++m_src_vertex;
153                 m_prev_status = m_status;
154                 m_status = out_vertices;
155                 m_out_vertex = 0;
156                 break;
157 
158             case close_first:
159                 m_status = outline2;
160                 cmd = path_cmd_move_to;
161 
162             case outline2:
163                 if(m_src_vertex <= unsigned(m_closed == 0))
164                 {
165                     m_status = end_poly2;
166                     m_prev_status = stop;
167                     break;
168                 }
169 
170                 --m_src_vertex;
171                 m_stroker.calc_join(m_out_vertices,
172                                     m_src_vertices.next(m_src_vertex),
173                                     m_src_vertices.curr(m_src_vertex),
174                                     m_src_vertices.prev(m_src_vertex),
175                                     m_src_vertices.curr(m_src_vertex).dist,
176                                     m_src_vertices.prev(m_src_vertex).dist);
177 
178                 m_prev_status = m_status;
179                 m_status = out_vertices;
180                 m_out_vertex = 0;
181                 break;
182 
183             case out_vertices:
184                 if(m_out_vertex >= m_out_vertices.size())
185                 {
186                     m_status = m_prev_status;
187                 }
188                 else
189                 {
190                     const point_d& c = m_out_vertices[m_out_vertex++];
191                     *x = c.x;
192                     *y = c.y;
193                     return cmd;
194                 }
195                 break;
196 
197             case end_poly1:
198                 m_status = m_prev_status;
199                 return path_cmd_end_poly | path_flags_close | path_flags_ccw;
200 
201             case end_poly2:
202                 m_status = m_prev_status;
203                 return path_cmd_end_poly | path_flags_close | path_flags_cw;
204 
205             case stop:
206                 cmd = path_cmd_stop;
207                 break;
208             }
209         }
210         return cmd;
211     }
212 
213 }
214