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