1
2 //----------------------------------------------------------------------------
3 // Anti-Grain Geometry - Version 2.3
4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
5 //
6 // Permission to copy, use, modify, sell and distribute this software
7 // is granted provided this copyright notice appears in all copies.
8 // This software is provided "as is" without express or implied
9 // warranty, and with no claim as to its suitability for any purpose.
10 //
11 //----------------------------------------------------------------------------
12 // Contact: mcseem@antigrain.com
13 // mcseemagg@yahoo.com
14 // http://www.antigrain.com
15 //----------------------------------------------------------------------------
16 //
17 // Line dash generator
18 //
19 //----------------------------------------------------------------------------
20
21 #include "agg_shorten_path.h"
22 #include "agg_vcgen_dash.h"
23 #include "core/fxcrt/fx_basic.h"
24
25 namespace agg
26 {
vcgen_dash()27 vcgen_dash::vcgen_dash() :
28 m_total_dash_len(0),
29 m_num_dashes(0),
30 m_dash_start(0),
31 m_shorten(0),
32 m_curr_dash_start(0),
33 m_curr_dash(0),
34 m_src_vertices(),
35 m_closed(0),
36 m_status(initial),
37 m_src_vertex(0)
38 {
39 }
remove_all_dashes()40 void vcgen_dash::remove_all_dashes()
41 {
42 m_total_dash_len = 0;
43 m_num_dashes = 0;
44 m_curr_dash_start = 0;
45 m_curr_dash = 0;
46 }
add_dash(FX_FLOAT dash_len,FX_FLOAT gap_len)47 void vcgen_dash::add_dash(FX_FLOAT dash_len, FX_FLOAT gap_len)
48 {
49 if(m_num_dashes < max_dashes) {
50 m_total_dash_len += dash_len + gap_len;
51 m_dashes[m_num_dashes++] = dash_len;
52 m_dashes[m_num_dashes++] = gap_len;
53 }
54 }
dash_start(FX_FLOAT ds)55 void vcgen_dash::dash_start(FX_FLOAT ds)
56 {
57 m_dash_start = ds;
58 calc_dash_start(FXSYS_fabs(ds));
59 }
calc_dash_start(FX_FLOAT ds)60 void vcgen_dash::calc_dash_start(FX_FLOAT ds)
61 {
62 m_curr_dash = 0;
63 m_curr_dash_start = 0;
64 while(ds > 0) {
65 if(ds > m_dashes[m_curr_dash]) {
66 ds -= m_dashes[m_curr_dash];
67 ++m_curr_dash;
68 m_curr_dash_start = 0;
69 if(m_curr_dash >= m_num_dashes) {
70 m_curr_dash = 0;
71 }
72 } else {
73 m_curr_dash_start = ds;
74 ds = 0;
75 }
76 }
77 }
remove_all()78 void vcgen_dash::remove_all()
79 {
80 m_status = initial;
81 m_src_vertices.remove_all();
82 m_closed = 0;
83 }
add_vertex(FX_FLOAT x,FX_FLOAT y,unsigned cmd)84 void vcgen_dash::add_vertex(FX_FLOAT x, FX_FLOAT y, unsigned cmd)
85 {
86 m_status = initial;
87 if(is_move_to(cmd)) {
88 m_src_vertices.modify_last(vertex_dist(x, y));
89 } else {
90 if(is_vertex(cmd)) {
91 m_src_vertices.add(vertex_dist(x, y));
92 } else {
93 m_closed = get_close_flag(cmd);
94 }
95 }
96 }
rewind(unsigned)97 void vcgen_dash::rewind(unsigned)
98 {
99 if(m_status == initial) {
100 m_src_vertices.close(m_closed != 0);
101 shorten_path(m_src_vertices, m_shorten, m_closed);
102 }
103 m_status = ready;
104 m_src_vertex = 0;
105 }
vertex(FX_FLOAT * x,FX_FLOAT * y)106 unsigned vcgen_dash::vertex(FX_FLOAT* x, FX_FLOAT* y)
107 {
108 unsigned cmd = path_cmd_move_to;
109 while(!is_stop(cmd)) {
110 switch(m_status) {
111 case initial:
112 rewind(0);
113 case ready:
114 if(m_num_dashes < 2 || m_src_vertices.size() < 2) {
115 cmd = path_cmd_stop;
116 break;
117 }
118 m_status = polyline;
119 m_src_vertex = 1;
120 m_v1 = &m_src_vertices[0];
121 m_v2 = &m_src_vertices[1];
122 m_curr_rest = m_v1->dist;
123 *x = m_v1->x;
124 *y = m_v1->y;
125 if(m_dash_start >= 0) {
126 calc_dash_start(m_dash_start);
127 }
128 return path_cmd_move_to;
129 case polyline: {
130 FX_FLOAT dash_rest = m_dashes[m_curr_dash] - m_curr_dash_start;
131 unsigned cmd = (m_curr_dash & 1) ?
132 path_cmd_move_to :
133 path_cmd_line_to;
134 if(m_curr_rest > dash_rest) {
135 m_curr_rest -= dash_rest;
136 ++m_curr_dash;
137 if(m_curr_dash >= m_num_dashes) {
138 m_curr_dash = 0;
139 }
140 m_curr_dash_start = 0;
141 *x = m_v2->x - (m_v2->x - m_v1->x) * m_curr_rest / m_v1->dist;
142 *y = m_v2->y - (m_v2->y - m_v1->y) * m_curr_rest / m_v1->dist;
143 } else {
144 m_curr_dash_start += m_curr_rest;
145 *x = m_v2->x;
146 *y = m_v2->y;
147 ++m_src_vertex;
148 m_v1 = m_v2;
149 m_curr_rest = m_v1->dist;
150 if(m_closed) {
151 if(m_src_vertex > m_src_vertices.size()) {
152 m_status = stop;
153 } else {
154 m_v2 = &m_src_vertices
155 [
156 (m_src_vertex >= m_src_vertices.size()) ? 0 :
157 m_src_vertex
158 ];
159 }
160 } else {
161 if(m_src_vertex >= m_src_vertices.size()) {
162 m_status = stop;
163 } else {
164 m_v2 = &m_src_vertices[m_src_vertex];
165 }
166 }
167 }
168 return cmd;
169 }
170 break;
171 case stop:
172 cmd = path_cmd_stop;
173 break;
174 }
175 }
176 return path_cmd_stop;
177 }
178 }
179