xref: /haiku/src/libs/agg/src/agg_vcgen_stroke.cpp (revision 93aeb8c3bc3f13cb1f282e3e749258a23790d947)
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.2
3 // Copyright (C) 2002-2004 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     //------------------------------------------------------------------------
27     vcgen_stroke::vcgen_stroke() :
28         m_src_vertices(),
29         m_out_vertices(),
30         m_width(0.5),
31         m_miter_limit(4.0),
32         m_inner_miter_limit(1.0 + 1.0/64.0),
33         m_approx_scale(1.0),
34         m_shorten(0.0),
35         m_line_cap(butt_cap),
36         m_line_join(miter_join),
37         m_inner_line_join(miter_join_revert),
38         m_closed(0),
39         m_status(initial),
40         m_src_vertex(0),
41         m_out_vertex(0)
42     {
43     }
44 
45 
46     //------------------------------------------------------------------------
47     void vcgen_stroke::miter_limit_theta(double t)
48     {
49         m_miter_limit = 1.0 / sin(t * 0.5) ;
50     }
51 
52 
53     //------------------------------------------------------------------------
54     void vcgen_stroke::remove_all()
55     {
56         m_src_vertices.remove_all();
57         m_closed = 0;
58         m_status = initial;
59     }
60 
61 
62     //------------------------------------------------------------------------
63     void vcgen_stroke::add_vertex(double x, double y, unsigned cmd)
64     {
65         m_status = initial;
66         if(is_move_to(cmd))
67         {
68             m_src_vertices.modify_last(vertex_dist(x, y));
69         }
70         else
71         {
72             if(is_vertex(cmd))
73             {
74                 m_src_vertices.add(vertex_dist(x, y));
75             }
76             else
77             {
78                 m_closed = get_close_flag(cmd);
79             }
80         }
81     }
82 
83 
84     //------------------------------------------------------------------------
85     void vcgen_stroke::rewind(unsigned)
86     {
87         if(m_status == initial)
88         {
89             m_src_vertices.close(m_closed != 0);
90             shorten_path(m_src_vertices, m_shorten, m_closed);
91             if(m_src_vertices.size() < 3) m_closed = 0;
92         }
93         m_status = ready;
94         m_src_vertex = 0;
95         m_out_vertex = 0;
96     }
97 
98 
99     //------------------------------------------------------------------------
100     unsigned vcgen_stroke::vertex(double* x, double* y)
101     {
102         unsigned cmd = path_cmd_line_to;
103         while(!is_stop(cmd))
104         {
105             switch(m_status)
106             {
107             case initial:
108                 rewind(0);
109 
110             case ready:
111                 if(m_src_vertices.size() < 2 + unsigned(m_closed != 0))
112                 {
113                     cmd = path_cmd_stop;
114                     break;
115                 }
116                 m_status = m_closed ? outline1 : cap1;
117                 cmd = path_cmd_move_to;
118                 m_src_vertex = 0;
119                 m_out_vertex = 0;
120                 break;
121 
122             case cap1:
123                 stroke_calc_cap(m_out_vertices,
124                                 m_src_vertices[0],
125                                 m_src_vertices[1],
126                                 m_src_vertices[0].dist,
127                                 m_line_cap,
128                                 m_width,
129                                 m_approx_scale);
130                 m_src_vertex = 1;
131                 m_prev_status = outline1;
132                 m_status = out_vertices;
133                 m_out_vertex = 0;
134                 break;
135 
136             case cap2:
137                 stroke_calc_cap(m_out_vertices,
138                                 m_src_vertices[m_src_vertices.size() - 1],
139                                 m_src_vertices[m_src_vertices.size() - 2],
140                                 m_src_vertices[m_src_vertices.size() - 2].dist,
141                                 m_line_cap,
142                                 m_width,
143                                 m_approx_scale);
144                 m_prev_status = outline2;
145                 m_status = out_vertices;
146                 m_out_vertex = 0;
147                 break;
148 
149             case outline1:
150                 if(m_closed)
151                 {
152                     if(m_src_vertex >= m_src_vertices.size())
153                     {
154                         m_prev_status = close_first;
155                         m_status = end_poly1;
156                         break;
157                     }
158                 }
159                 else
160                 {
161                     if(m_src_vertex >= m_src_vertices.size() - 1)
162                     {
163                         m_status = cap2;
164                         break;
165                     }
166                 }
167                 stroke_calc_join(m_out_vertices,
168                                  m_src_vertices.prev(m_src_vertex),
169                                  m_src_vertices.curr(m_src_vertex),
170                                  m_src_vertices.next(m_src_vertex),
171                                  m_src_vertices.prev(m_src_vertex).dist,
172                                  m_src_vertices.curr(m_src_vertex).dist,
173                                  m_width,
174                                  m_line_join,
175                                  m_inner_line_join,
176                                  m_miter_limit,
177                                  m_inner_miter_limit,
178                                  m_approx_scale);
179                 ++m_src_vertex;
180                 m_prev_status = m_status;
181                 m_status = out_vertices;
182                 m_out_vertex = 0;
183                 break;
184 
185             case close_first:
186                 m_status = outline2;
187                 cmd = path_cmd_move_to;
188 
189             case outline2:
190                 if(m_src_vertex <= unsigned(m_closed == 0))
191                 {
192                     m_status = end_poly2;
193                     m_prev_status = stop;
194                     break;
195                 }
196 
197                 --m_src_vertex;
198                 stroke_calc_join(m_out_vertices,
199                                  m_src_vertices.next(m_src_vertex),
200                                  m_src_vertices.curr(m_src_vertex),
201                                  m_src_vertices.prev(m_src_vertex),
202                                  m_src_vertices.curr(m_src_vertex).dist,
203                                  m_src_vertices.prev(m_src_vertex).dist,
204                                  m_width,
205                                  m_line_join,
206                                  m_inner_line_join,
207                                  m_miter_limit,
208                                  m_inner_miter_limit,
209                                  m_approx_scale);
210 
211                 m_prev_status = m_status;
212                 m_status = out_vertices;
213                 m_out_vertex = 0;
214                 break;
215 
216             case out_vertices:
217                 if(m_out_vertex >= m_out_vertices.size())
218                 {
219                     m_status = m_prev_status;
220                 }
221                 else
222                 {
223                     const point_type& c = m_out_vertices[m_out_vertex++];
224                     *x = c.x;
225                     *y = c.y;
226                     return cmd;
227                 }
228                 break;
229 
230             case end_poly1:
231                 m_status = m_prev_status;
232                 return path_cmd_end_poly | path_flags_close | path_flags_ccw;
233 
234             case end_poly2:
235                 m_status = m_prev_status;
236                 return path_cmd_end_poly | path_flags_close | path_flags_cw;
237 
238             case stop:
239                 cmd = path_cmd_stop;
240                 break;
241             }
242         }
243         return cmd;
244     }
245 
246 }
247