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/include/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