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// Line dash generator
17//
18//----------------------------------------------------------------------------
19
20#include <math.h>
21#include "agg_vcgen_dash.h"
22#include "agg_shorten_path.h"
23
24namespace agg
25{
26
27    //------------------------------------------------------------------------
28    vcgen_dash::vcgen_dash() :
29        m_total_dash_len(0.0),
30        m_num_dashes(0),
31        m_dash_start(0.0),
32        m_shorten(0.0),
33        m_curr_dash_start(0.0),
34        m_curr_dash(0),
35        m_src_vertices(),
36        m_closed(0),
37        m_status(initial),
38        m_src_vertex(0)
39    {
40    }
41
42
43
44    //------------------------------------------------------------------------
45    void vcgen_dash::remove_all_dashes()
46    {
47        m_total_dash_len = 0.0;
48        m_num_dashes = 0;
49        m_curr_dash_start = 0.0;
50        m_curr_dash = 0;
51    }
52
53
54    //------------------------------------------------------------------------
55    void vcgen_dash::add_dash(double dash_len, double gap_len)
56    {
57        if(m_num_dashes < max_dashes - 1)
58        {
59            m_total_dash_len += dash_len + gap_len;
60            m_dashes[m_num_dashes++] = dash_len;
61            m_dashes[m_num_dashes++] = gap_len;
62        }
63    }
64
65
66    //------------------------------------------------------------------------
67    void vcgen_dash::dash_start(double ds)
68    {
69        m_dash_start = ds;
70        calc_dash_start(fabs(ds));
71    }
72
73
74    //------------------------------------------------------------------------
75    void vcgen_dash::calc_dash_start(double ds)
76    {
77        m_curr_dash = 0;
78        m_curr_dash_start = 0.0;
79        while(ds > 0.0)
80        {
81            if(ds > m_dashes[m_curr_dash])
82            {
83                ds -= m_dashes[m_curr_dash];
84                ++m_curr_dash;
85                m_curr_dash_start = 0.0;
86                if(m_curr_dash >= m_num_dashes) m_curr_dash = 0;
87            }
88            else
89            {
90                m_curr_dash_start = ds;
91                ds = 0.0;
92            }
93        }
94    }
95
96
97    //------------------------------------------------------------------------
98    void vcgen_dash::remove_all()
99    {
100        m_status = initial;
101        m_src_vertices.remove_all();
102        m_closed = 0;
103    }
104
105
106    //------------------------------------------------------------------------
107    void vcgen_dash::add_vertex(double x, double y, unsigned cmd)
108    {
109        m_status = initial;
110        if(is_move_to(cmd))
111        {
112            m_src_vertices.modify_last(vertex_dist(x, y));
113        }
114        else
115        {
116            if(is_vertex(cmd))
117            {
118                m_src_vertices.add(vertex_dist(x, y));
119            }
120            else
121            {
122                m_closed = get_close_flag(cmd);
123            }
124        }
125    }
126
127
128    //------------------------------------------------------------------------
129    void vcgen_dash::rewind(unsigned)
130    {
131        if(m_status == initial)
132        {
133            m_src_vertices.close(m_closed != 0);
134            shorten_path(m_src_vertices, m_shorten, m_closed);
135        }
136        m_status = ready;
137        m_src_vertex = 0;
138    }
139
140
141    //------------------------------------------------------------------------
142    unsigned vcgen_dash::vertex(double* x, double* y)
143    {
144        unsigned cmd = path_cmd_move_to;
145        while(!is_stop(cmd))
146        {
147            switch(m_status)
148            {
149            case initial:
150                rewind(0);
151
152            case ready:
153                if(m_num_dashes < 2 || m_src_vertices.size() < 2)
154                {
155                    cmd = path_cmd_stop;
156                    break;
157                }
158                m_status = polyline;
159                m_src_vertex = 1;
160                m_v1 = &m_src_vertices[0];
161                m_v2 = &m_src_vertices[1];
162                m_curr_rest = m_v1->dist;
163                *x = m_v1->x;
164                *y = m_v1->y;
165                if(m_dash_start >= 0.0) calc_dash_start(m_dash_start);
166                return path_cmd_move_to;
167
168            case polyline:
169                {
170                    double dash_rest = m_dashes[m_curr_dash] - m_curr_dash_start;
171
172                    unsigned cmd = (m_curr_dash & 1) ?
173                                   path_cmd_move_to :
174                                   path_cmd_line_to;
175
176                    if(m_curr_rest > dash_rest)
177                    {
178                        m_curr_rest -= dash_rest;
179                        ++m_curr_dash;
180                        if(m_curr_dash >= m_num_dashes) m_curr_dash = 0;
181                        m_curr_dash_start = 0.0;
182                        *x = m_v2->x - (m_v2->x - m_v1->x) * m_curr_rest / m_v1->dist;
183                        *y = m_v2->y - (m_v2->y - m_v1->y) * m_curr_rest / m_v1->dist;
184                    }
185                    else
186                    {
187                        m_curr_dash_start += m_curr_rest;
188                        *x = m_v2->x;
189                        *y = m_v2->y;
190                        ++m_src_vertex;
191                        m_v1 = m_v2;
192                        m_curr_rest = m_v1->dist;
193                        if(m_closed)
194                        {
195                            if(m_src_vertex > m_src_vertices.size())
196                            {
197                                m_status = stop;
198                            }
199                            else
200                            {
201                                m_v2 = &m_src_vertices
202                                [
203                                    (m_src_vertex >= m_src_vertices.size()) ? 0 :
204                                    m_src_vertex
205                                ];
206                            }
207                        }
208                        else
209                        {
210                            if(m_src_vertex >= m_src_vertices.size())
211                            {
212                                m_status = stop;
213                            }
214                            else
215                            {
216                                m_v2 = &m_src_vertices[m_src_vertex];
217                            }
218                        }
219                    }
220                    return cmd;
221                }
222                break;
223
224            case stop:
225                cmd = path_cmd_stop;
226                break;
227            }
228
229        }
230        return path_cmd_stop;
231    }
232
233
234}
235
236