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 
23 namespace agg
24 {
25 
26     //------------------------------------------------------------------------
vcgen_contour()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     //------------------------------------------------------------------------
remove_all()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     //------------------------------------------------------------------------
add_vertex(double x,double y,unsigned cmd)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     //------------------------------------------------------------------------
rewind(unsigned)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     //------------------------------------------------------------------------
vertex(double * x,double * y)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