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// Contour generator
17//
18//----------------------------------------------------------------------------
19
20#include <math.h>
21#include "agg_vcgen_contour.h"
22
23namespace agg
24{
25
26    //------------------------------------------------------------------------
27    vcgen_contour::vcgen_contour() :
28        m_stroker(),
29        m_width(1),
30        m_src_vertices(),
31        m_out_vertices(),
32        m_status(initial),
33        m_src_vertex(0),
34        m_closed(0),
35        m_orientation(0),
36        m_auto_detect(false)
37    {
38    }
39
40    //------------------------------------------------------------------------
41    void vcgen_contour::remove_all()
42    {
43        m_src_vertices.remove_all();
44        m_closed = 0;
45        m_orientation = 0;
46        m_status = initial;
47    }
48
49    //------------------------------------------------------------------------
50    void vcgen_contour::add_vertex(double x, double y, unsigned cmd)
51    {
52        m_status = initial;
53        if(is_move_to(cmd))
54        {
55            m_src_vertices.modify_last(vertex_dist(x, y));
56        }
57        else
58        {
59            if(is_vertex(cmd))
60            {
61                m_src_vertices.add(vertex_dist(x, y));
62            }
63            else
64            {
65                if(is_end_poly(cmd))
66                {
67                    m_closed = get_close_flag(cmd);
68                    if(m_orientation == path_flags_none)
69                    {
70                        m_orientation = get_orientation(cmd);
71                    }
72                }
73            }
74        }
75    }
76
77    //------------------------------------------------------------------------
78    void vcgen_contour::rewind(unsigned)
79    {
80        if(m_status == initial)
81        {
82            m_src_vertices.close(true);
83            if(m_auto_detect)
84            {
85                if(!is_oriented(m_orientation))
86                {
87                    m_orientation = (calc_polygon_area(m_src_vertices) > 0.0) ?
88                                    path_flags_ccw :
89                                    path_flags_cw;
90                }
91            }
92            if(is_oriented(m_orientation))
93            {
94                m_stroker.width(is_ccw(m_orientation) ? m_width : -m_width);
95            }
96        }
97        m_status = ready;
98        m_src_vertex = 0;
99    }
100
101    //------------------------------------------------------------------------
102    unsigned vcgen_contour::vertex(double* x, double* y)
103    {
104        unsigned cmd = path_cmd_line_to;
105        while(!is_stop(cmd))
106        {
107            switch(m_status)
108            {
109            case initial:
110                rewind(0);
111
112            case ready:
113                if(m_src_vertices.size() < 2 + unsigned(m_closed != 0))
114                {
115                    cmd = path_cmd_stop;
116                    break;
117                }
118                m_status = outline;
119                cmd = path_cmd_move_to;
120                m_src_vertex = 0;
121                m_out_vertex = 0;
122
123            case outline:
124                if(m_src_vertex >= m_src_vertices.size())
125                {
126                    m_status = end_poly;
127                    break;
128                }
129                m_stroker.calc_join(m_out_vertices,
130                                    m_src_vertices.prev(m_src_vertex),
131                                    m_src_vertices.curr(m_src_vertex),
132                                    m_src_vertices.next(m_src_vertex),
133                                    m_src_vertices.prev(m_src_vertex).dist,
134                                    m_src_vertices.curr(m_src_vertex).dist);
135                ++m_src_vertex;
136                m_status = out_vertices;
137                m_out_vertex = 0;
138
139            case out_vertices:
140                if(m_out_vertex >= m_out_vertices.size())
141                {
142                    m_status = outline;
143                }
144                else
145                {
146                    const point_d& c = m_out_vertices[m_out_vertex++];
147                    *x = c.x;
148                    *y = c.y;
149                    return cmd;
150                }
151                break;
152
153            case end_poly:
154                if(!m_closed) return path_cmd_stop;
155                m_status = stop;
156                return path_cmd_end_poly | path_flags_close | path_flags_ccw;
157
158            case stop:
159                return path_cmd_stop;
160            }
161        }
162        return cmd;
163    }
164
165}
166