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#include "../../../../include/fxcrt/fx_basic.h"
21#include "agg_vcgen_dash.h"
22#include "agg_shorten_path.h"
23namespace agg
24{
25vcgen_dash::vcgen_dash() :
26    m_total_dash_len(0),
27    m_num_dashes(0),
28    m_dash_start(0),
29    m_shorten(0),
30    m_curr_dash_start(0),
31    m_curr_dash(0),
32    m_src_vertices(),
33    m_closed(0),
34    m_status(initial),
35    m_src_vertex(0)
36{
37}
38void vcgen_dash::remove_all_dashes()
39{
40    m_total_dash_len = 0;
41    m_num_dashes = 0;
42    m_curr_dash_start = 0;
43    m_curr_dash = 0;
44}
45void vcgen_dash::add_dash(FX_FLOAT dash_len, FX_FLOAT gap_len)
46{
47    if(m_num_dashes < max_dashes) {
48        m_total_dash_len += dash_len + gap_len;
49        m_dashes[m_num_dashes++] = dash_len;
50        m_dashes[m_num_dashes++] = gap_len;
51    }
52}
53void vcgen_dash::dash_start(FX_FLOAT ds)
54{
55    m_dash_start = ds;
56    calc_dash_start(FXSYS_fabs(ds));
57}
58void vcgen_dash::calc_dash_start(FX_FLOAT ds)
59{
60    m_curr_dash = 0;
61    m_curr_dash_start = 0;
62    while(ds > 0) {
63        if(ds > m_dashes[m_curr_dash]) {
64            ds -= m_dashes[m_curr_dash];
65            ++m_curr_dash;
66            m_curr_dash_start = 0;
67            if(m_curr_dash >= m_num_dashes) {
68                m_curr_dash = 0;
69            }
70        } else {
71            m_curr_dash_start = ds;
72            ds = 0;
73        }
74    }
75}
76void vcgen_dash::remove_all()
77{
78    m_status = initial;
79    m_src_vertices.remove_all();
80    m_closed = 0;
81}
82void vcgen_dash::add_vertex(FX_FLOAT x, FX_FLOAT y, unsigned cmd)
83{
84    m_status = initial;
85    if(is_move_to(cmd)) {
86        m_src_vertices.modify_last(vertex_dist(x, y));
87    } else {
88        if(is_vertex(cmd)) {
89            m_src_vertices.add(vertex_dist(x, y));
90        } else {
91            m_closed = get_close_flag(cmd);
92        }
93    }
94}
95void vcgen_dash::rewind(unsigned)
96{
97    if(m_status == initial) {
98        m_src_vertices.close(m_closed != 0);
99        shorten_path(m_src_vertices, m_shorten, m_closed);
100    }
101    m_status = ready;
102    m_src_vertex = 0;
103}
104unsigned vcgen_dash::vertex(FX_FLOAT* x, FX_FLOAT* y)
105{
106    unsigned cmd = path_cmd_move_to;
107    while(!is_stop(cmd)) {
108        switch(m_status) {
109            case initial:
110                rewind(0);
111            case ready:
112                if(m_num_dashes < 2 || m_src_vertices.size() < 2) {
113                    cmd = path_cmd_stop;
114                    break;
115                }
116                m_status = polyline;
117                m_src_vertex = 1;
118                m_v1 = &m_src_vertices[0];
119                m_v2 = &m_src_vertices[1];
120                m_curr_rest = m_v1->dist;
121                *x = m_v1->x;
122                *y = m_v1->y;
123                if(m_dash_start >= 0) {
124                    calc_dash_start(m_dash_start);
125                }
126                return path_cmd_move_to;
127            case polyline: {
128                    FX_FLOAT dash_rest = m_dashes[m_curr_dash] - m_curr_dash_start;
129                    unsigned cmd = (m_curr_dash & 1) ?
130                                   path_cmd_move_to :
131                                   path_cmd_line_to;
132                    if(m_curr_rest > dash_rest) {
133                        m_curr_rest -= dash_rest;
134                        ++m_curr_dash;
135                        if(m_curr_dash >= m_num_dashes) {
136                            m_curr_dash = 0;
137                        }
138                        m_curr_dash_start = 0;
139                        *x = m_v2->x - (m_v2->x - m_v1->x) * m_curr_rest / m_v1->dist;
140                        *y = m_v2->y - (m_v2->y - m_v1->y) * m_curr_rest / m_v1->dist;
141                    } else {
142                        m_curr_dash_start += m_curr_rest;
143                        *x = m_v2->x;
144                        *y = m_v2->y;
145                        ++m_src_vertex;
146                        m_v1 = m_v2;
147                        m_curr_rest = m_v1->dist;
148                        if(m_closed) {
149                            if(m_src_vertex > m_src_vertices.size()) {
150                                m_status = stop;
151                            } else {
152                                m_v2 = &m_src_vertices
153                                       [
154                                           (m_src_vertex >= m_src_vertices.size()) ? 0 :
155                                           m_src_vertex
156                                       ];
157                            }
158                        } else {
159                            if(m_src_vertex >= m_src_vertices.size()) {
160                                m_status = stop;
161                            } else {
162                                m_v2 = &m_src_vertices[m_src_vertex];
163                            }
164                        }
165                    }
166                    return cmd;
167                }
168                break;
169            case stop:
170                cmd = path_cmd_stop;
171                break;
172        }
173    }
174    return path_cmd_stop;
175}
176}
177