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