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 // Stroke generator 17 // 18 //---------------------------------------------------------------------------- 19 #include <math.h> 20 #include "agg_vcgen_stroke.h" 21 #include "agg_shorten_path.h" 22 23 namespace agg 24 { 25 26 //------------------------------------------------------------------------ 27 vcgen_stroke::vcgen_stroke() : 28 m_stroker(), 29 m_src_vertices(), 30 m_out_vertices(), 31 m_shorten(0.0), 32 m_closed(0), 33 m_status(initial), 34 m_src_vertex(0), 35 m_out_vertex(0) 36 { 37 } 38 39 //------------------------------------------------------------------------ 40 void vcgen_stroke::remove_all() 41 { 42 m_src_vertices.remove_all(); 43 m_closed = 0; 44 m_status = initial; 45 } 46 47 48 //------------------------------------------------------------------------ 49 void vcgen_stroke::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 m_closed = get_close_flag(cmd); 65 } 66 } 67 } 68 69 //------------------------------------------------------------------------ 70 void vcgen_stroke::rewind(unsigned) 71 { 72 if(m_status == initial) 73 { 74 m_src_vertices.close(m_closed != 0); 75 shorten_path(m_src_vertices, m_shorten, m_closed); 76 if(m_src_vertices.size() < 3) m_closed = 0; 77 } 78 m_status = ready; 79 m_src_vertex = 0; 80 m_out_vertex = 0; 81 } 82 83 84 //------------------------------------------------------------------------ 85 unsigned vcgen_stroke::vertex(double* x, double* y) 86 { 87 unsigned cmd = path_cmd_line_to; 88 while(!is_stop(cmd)) 89 { 90 switch(m_status) 91 { 92 case initial: 93 rewind(0); 94 95 case ready: 96 if(m_src_vertices.size() < 2 + unsigned(m_closed != 0)) 97 { 98 cmd = path_cmd_stop; 99 break; 100 } 101 m_status = m_closed ? outline1 : cap1; 102 cmd = path_cmd_move_to; 103 m_src_vertex = 0; 104 m_out_vertex = 0; 105 break; 106 107 case cap1: 108 m_stroker.calc_cap(m_out_vertices, 109 m_src_vertices[0], 110 m_src_vertices[1], 111 m_src_vertices[0].dist); 112 m_src_vertex = 1; 113 m_prev_status = outline1; 114 m_status = out_vertices; 115 m_out_vertex = 0; 116 break; 117 118 case cap2: 119 m_stroker.calc_cap(m_out_vertices, 120 m_src_vertices[m_src_vertices.size() - 1], 121 m_src_vertices[m_src_vertices.size() - 2], 122 m_src_vertices[m_src_vertices.size() - 2].dist); 123 m_prev_status = outline2; 124 m_status = out_vertices; 125 m_out_vertex = 0; 126 break; 127 128 case outline1: 129 if(m_closed) 130 { 131 if(m_src_vertex >= m_src_vertices.size()) 132 { 133 m_prev_status = close_first; 134 m_status = end_poly1; 135 break; 136 } 137 } 138 else 139 { 140 if(m_src_vertex >= m_src_vertices.size() - 1) 141 { 142 m_status = cap2; 143 break; 144 } 145 } 146 m_stroker.calc_join(m_out_vertices, 147 m_src_vertices.prev(m_src_vertex), 148 m_src_vertices.curr(m_src_vertex), 149 m_src_vertices.next(m_src_vertex), 150 m_src_vertices.prev(m_src_vertex).dist, 151 m_src_vertices.curr(m_src_vertex).dist); 152 ++m_src_vertex; 153 m_prev_status = m_status; 154 m_status = out_vertices; 155 m_out_vertex = 0; 156 break; 157 158 case close_first: 159 m_status = outline2; 160 cmd = path_cmd_move_to; 161 162 case outline2: 163 if(m_src_vertex <= unsigned(m_closed == 0)) 164 { 165 m_status = end_poly2; 166 m_prev_status = stop; 167 break; 168 } 169 170 --m_src_vertex; 171 m_stroker.calc_join(m_out_vertices, 172 m_src_vertices.next(m_src_vertex), 173 m_src_vertices.curr(m_src_vertex), 174 m_src_vertices.prev(m_src_vertex), 175 m_src_vertices.curr(m_src_vertex).dist, 176 m_src_vertices.prev(m_src_vertex).dist); 177 178 m_prev_status = m_status; 179 m_status = out_vertices; 180 m_out_vertex = 0; 181 break; 182 183 case out_vertices: 184 if(m_out_vertex >= m_out_vertices.size()) 185 { 186 m_status = m_prev_status; 187 } 188 else 189 { 190 const point_d& c = m_out_vertices[m_out_vertex++]; 191 *x = c.x; 192 *y = c.y; 193 return cmd; 194 } 195 break; 196 197 case end_poly1: 198 m_status = m_prev_status; 199 return path_cmd_end_poly | path_flags_close | path_flags_ccw; 200 201 case end_poly2: 202 m_status = m_prev_status; 203 return path_cmd_end_poly | path_flags_close | path_flags_cw; 204 205 case stop: 206 cmd = path_cmd_stop; 207 break; 208 } 209 } 210 return cmd; 211 } 212 213 } 214